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;
   26mod 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 editor_tests;
   44#[cfg(test)]
   45mod inline_completion_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   52use aho_corasick::AhoCorasick;
   53use anyhow::{Context as _, Result, anyhow};
   54use blink_manager::BlinkManager;
   55use buffer_diff::DiffHunkStatus;
   56use client::{Collaborator, ParticipantIndex};
   57use clock::ReplicaId;
   58use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   59use convert_case::{Case, Casing};
   60use display_map::*;
   61pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   62use editor_settings::GoToDefinitionFallback;
   63pub use editor_settings::{
   64    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   65    ShowScrollbar,
   66};
   67pub use editor_settings_controls::*;
   68use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   69pub use element::{
   70    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   71};
   72use feature_flags::{Debugger, FeatureFlagAppExt};
   73use futures::{
   74    FutureExt,
   75    future::{self, Shared, join},
   76};
   77use fuzzy::StringMatchCandidate;
   78
   79use ::git::Restore;
   80use code_context_menus::{
   81    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   82    CompletionsMenu, ContextMenuOrigin,
   83};
   84use git::blame::{GitBlame, GlobalBlameRenderer};
   85use gpui::{
   86    Action, Animation, AnimationExt, AnyElement, AnyWeakEntity, App, AppContext,
   87    AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry,
   88    ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter,
   89    FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla,
   90    KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render,
   91    SharedString, Size, Stateful, Styled, StyledText, Subscription, Task, TextStyle,
   92    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
   93    WeakFocusHandle, Window, div, impl_actions, point, prelude::*, pulsating_between, px, relative,
   94    size,
   95};
   96use highlight_matching_bracket::refresh_matching_bracket_highlights;
   97use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
   98pub use hover_popover::hover_markdown_style;
   99use hover_popover::{HoverState, hide_hover};
  100use indent_guides::ActiveIndentGuidesState;
  101use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  102pub use inline_completion::Direction;
  103use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  104pub use items::MAX_TAB_TITLE_LEN;
  105use itertools::Itertools;
  106use language::{
  107    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  108    CursorShape, Diagnostic, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText,
  109    IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
  110    TransactionId, TreeSitterOptions, WordsQuery,
  111    language_settings::{
  112        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  113        all_language_settings, language_settings,
  114    },
  115    point_from_lsp, text_diff_with_options,
  116};
  117use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  118use linked_editing_ranges::refresh_linked_ranges;
  119use mouse_context_menu::MouseContextMenu;
  120use persistence::DB;
  121use project::{
  122    ProjectPath,
  123    debugger::breakpoint_store::{
  124        BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  125    },
  126};
  127
  128pub use git::blame::BlameRenderer;
  129pub use proposed_changes_editor::{
  130    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  131};
  132use smallvec::smallvec;
  133use std::{cell::OnceCell, iter::Peekable};
  134use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  135
  136pub use lsp::CompletionContext;
  137use lsp::{
  138    CodeActionKind, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity,
  139    InsertTextFormat, InsertTextMode, LanguageServerId, LanguageServerName,
  140};
  141
  142use language::BufferSnapshot;
  143pub use lsp_ext::lsp_tasks;
  144use movement::TextLayoutDetails;
  145pub use multi_buffer::{
  146    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, RowInfo,
  147    ToOffset, ToPoint,
  148};
  149use multi_buffer::{
  150    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  151    MultiOrSingleBufferOffsetRange, PathKey, ToOffsetUtf16,
  152};
  153use parking_lot::Mutex;
  154use project::{
  155    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  156    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  157    TaskSourceKind,
  158    debugger::breakpoint_store::Breakpoint,
  159    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  160    project_settings::{GitGutterSetting, ProjectSettings},
  161};
  162use rand::prelude::*;
  163use rpc::{ErrorExt, proto::*};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  165use selections_collection::{
  166    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  167};
  168use serde::{Deserialize, Serialize};
  169use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  170use smallvec::SmallVec;
  171use snippet::Snippet;
  172use std::sync::Arc;
  173use std::{
  174    any::TypeId,
  175    borrow::Cow,
  176    cell::RefCell,
  177    cmp::{self, Ordering, Reverse},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    time::{Duration, Instant},
  184};
  185pub use sum_tree::Bias;
  186use sum_tree::TreeMap;
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Key, Tooltip, h_flex, prelude::*,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemHandle, PreviewTabsSettings},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::hover_links::{find_url, find_url_from_range};
  207use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  208
  209pub const FILE_HEADER_HEIGHT: u32 = 2;
  210pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  211pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  212const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  213const MAX_LINE_LEN: usize = 1024;
  214const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  215const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  216pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  217#[doc(hidden)]
  218pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  219
  220pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  221pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  222pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  223
  224pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  225pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  226pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  227
  228pub type RenderDiffHunkControlsFn = Arc<
  229    dyn Fn(
  230        u32,
  231        &DiffHunkStatus,
  232        Range<Anchor>,
  233        bool,
  234        Pixels,
  235        &Entity<Editor>,
  236        &mut Window,
  237        &mut App,
  238    ) -> AnyElement,
  239>;
  240
  241const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  242    alt: true,
  243    shift: true,
  244    control: false,
  245    platform: false,
  246    function: false,
  247};
  248
  249#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  250pub enum InlayId {
  251    InlineCompletion(usize),
  252    Hint(usize),
  253}
  254
  255impl InlayId {
  256    fn id(&self) -> usize {
  257        match self {
  258            Self::InlineCompletion(id) => *id,
  259            Self::Hint(id) => *id,
  260        }
  261    }
  262}
  263
  264pub enum DebugCurrentRowHighlight {}
  265enum DocumentHighlightRead {}
  266enum DocumentHighlightWrite {}
  267enum InputComposition {}
  268enum SelectedTextHighlight {}
  269
  270#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  271pub enum Navigated {
  272    Yes,
  273    No,
  274}
  275
  276impl Navigated {
  277    pub fn from_bool(yes: bool) -> Navigated {
  278        if yes { Navigated::Yes } else { Navigated::No }
  279    }
  280}
  281
  282#[derive(Debug, Clone, PartialEq, Eq)]
  283enum DisplayDiffHunk {
  284    Folded {
  285        display_row: DisplayRow,
  286    },
  287    Unfolded {
  288        is_created_file: bool,
  289        diff_base_byte_range: Range<usize>,
  290        display_row_range: Range<DisplayRow>,
  291        multi_buffer_range: Range<Anchor>,
  292        status: DiffHunkStatus,
  293    },
  294}
  295
  296pub enum HideMouseCursorOrigin {
  297    TypingAction,
  298    MovementAction,
  299}
  300
  301pub fn init_settings(cx: &mut App) {
  302    EditorSettings::register(cx);
  303}
  304
  305pub fn init(cx: &mut App) {
  306    init_settings(cx);
  307
  308    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  309
  310    workspace::register_project_item::<Editor>(cx);
  311    workspace::FollowableViewRegistry::register::<Editor>(cx);
  312    workspace::register_serializable_item::<Editor>(cx);
  313
  314    cx.observe_new(
  315        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  316            workspace.register_action(Editor::new_file);
  317            workspace.register_action(Editor::new_file_vertical);
  318            workspace.register_action(Editor::new_file_horizontal);
  319            workspace.register_action(Editor::cancel_language_server_work);
  320        },
  321    )
  322    .detach();
  323
  324    cx.on_action(move |_: &workspace::NewFile, cx| {
  325        let app_state = workspace::AppState::global(cx);
  326        if let Some(app_state) = app_state.upgrade() {
  327            workspace::open_new(
  328                Default::default(),
  329                app_state,
  330                cx,
  331                |workspace, window, cx| {
  332                    Editor::new_file(workspace, &Default::default(), window, cx)
  333                },
  334            )
  335            .detach();
  336        }
  337    });
  338    cx.on_action(move |_: &workspace::NewWindow, cx| {
  339        let app_state = workspace::AppState::global(cx);
  340        if let Some(app_state) = app_state.upgrade() {
  341            workspace::open_new(
  342                Default::default(),
  343                app_state,
  344                cx,
  345                |workspace, window, cx| {
  346                    cx.activate(true);
  347                    Editor::new_file(workspace, &Default::default(), window, cx)
  348                },
  349            )
  350            .detach();
  351        }
  352    });
  353}
  354
  355pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  356    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  357}
  358
  359pub struct SearchWithinRange;
  360
  361trait InvalidationRegion {
  362    fn ranges(&self) -> &[Range<Anchor>];
  363}
  364
  365#[derive(Clone, Debug, PartialEq)]
  366pub enum SelectPhase {
  367    Begin {
  368        position: DisplayPoint,
  369        add: bool,
  370        click_count: usize,
  371    },
  372    BeginColumnar {
  373        position: DisplayPoint,
  374        reset: bool,
  375        goal_column: u32,
  376    },
  377    Extend {
  378        position: DisplayPoint,
  379        click_count: usize,
  380    },
  381    Update {
  382        position: DisplayPoint,
  383        goal_column: u32,
  384        scroll_delta: gpui::Point<f32>,
  385    },
  386    End,
  387}
  388
  389#[derive(Clone, Debug)]
  390pub enum SelectMode {
  391    Character,
  392    Word(Range<Anchor>),
  393    Line(Range<Anchor>),
  394    All,
  395}
  396
  397#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  398pub enum EditorMode {
  399    SingleLine {
  400        auto_width: bool,
  401    },
  402    AutoHeight {
  403        max_lines: usize,
  404    },
  405    Full {
  406        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  407        scale_ui_elements_with_buffer_font_size: bool,
  408        /// When set to `true`, the editor will render a background for the active line.
  409        show_active_line_background: bool,
  410    },
  411}
  412
  413impl EditorMode {
  414    pub fn full() -> Self {
  415        Self::Full {
  416            scale_ui_elements_with_buffer_font_size: true,
  417            show_active_line_background: true,
  418        }
  419    }
  420
  421    pub fn is_full(&self) -> bool {
  422        matches!(self, Self::Full { .. })
  423    }
  424}
  425
  426#[derive(Copy, Clone, Debug)]
  427pub enum SoftWrap {
  428    /// Prefer not to wrap at all.
  429    ///
  430    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  431    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  432    GitDiff,
  433    /// Prefer a single line generally, unless an overly long line is encountered.
  434    None,
  435    /// Soft wrap lines that exceed the editor width.
  436    EditorWidth,
  437    /// Soft wrap lines at the preferred line length.
  438    Column(u32),
  439    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  440    Bounded(u32),
  441}
  442
  443#[derive(Clone)]
  444pub struct EditorStyle {
  445    pub background: Hsla,
  446    pub local_player: PlayerColor,
  447    pub text: TextStyle,
  448    pub scrollbar_width: Pixels,
  449    pub syntax: Arc<SyntaxTheme>,
  450    pub status: StatusColors,
  451    pub inlay_hints_style: HighlightStyle,
  452    pub inline_completion_styles: InlineCompletionStyles,
  453    pub unnecessary_code_fade: f32,
  454}
  455
  456impl Default for EditorStyle {
  457    fn default() -> Self {
  458        Self {
  459            background: Hsla::default(),
  460            local_player: PlayerColor::default(),
  461            text: TextStyle::default(),
  462            scrollbar_width: Pixels::default(),
  463            syntax: Default::default(),
  464            // HACK: Status colors don't have a real default.
  465            // We should look into removing the status colors from the editor
  466            // style and retrieve them directly from the theme.
  467            status: StatusColors::dark(),
  468            inlay_hints_style: HighlightStyle::default(),
  469            inline_completion_styles: InlineCompletionStyles {
  470                insertion: HighlightStyle::default(),
  471                whitespace: HighlightStyle::default(),
  472            },
  473            unnecessary_code_fade: Default::default(),
  474        }
  475    }
  476}
  477
  478pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  479    let show_background = language_settings::language_settings(None, None, cx)
  480        .inlay_hints
  481        .show_background;
  482
  483    HighlightStyle {
  484        color: Some(cx.theme().status().hint),
  485        background_color: show_background.then(|| cx.theme().status().hint_background),
  486        ..HighlightStyle::default()
  487    }
  488}
  489
  490pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  491    InlineCompletionStyles {
  492        insertion: HighlightStyle {
  493            color: Some(cx.theme().status().predictive),
  494            ..HighlightStyle::default()
  495        },
  496        whitespace: HighlightStyle {
  497            background_color: Some(cx.theme().status().created_background),
  498            ..HighlightStyle::default()
  499        },
  500    }
  501}
  502
  503type CompletionId = usize;
  504
  505pub(crate) enum EditDisplayMode {
  506    TabAccept,
  507    DiffPopover,
  508    Inline,
  509}
  510
  511enum InlineCompletion {
  512    Edit {
  513        edits: Vec<(Range<Anchor>, String)>,
  514        edit_preview: Option<EditPreview>,
  515        display_mode: EditDisplayMode,
  516        snapshot: BufferSnapshot,
  517    },
  518    Move {
  519        target: Anchor,
  520        snapshot: BufferSnapshot,
  521    },
  522}
  523
  524struct InlineCompletionState {
  525    inlay_ids: Vec<InlayId>,
  526    completion: InlineCompletion,
  527    completion_id: Option<SharedString>,
  528    invalidation_range: Range<Anchor>,
  529}
  530
  531enum EditPredictionSettings {
  532    Disabled,
  533    Enabled {
  534        show_in_menu: bool,
  535        preview_requires_modifier: bool,
  536    },
  537}
  538
  539enum InlineCompletionHighlight {}
  540
  541#[derive(Debug, Clone)]
  542struct InlineDiagnostic {
  543    message: SharedString,
  544    group_id: usize,
  545    is_primary: bool,
  546    start: Point,
  547    severity: DiagnosticSeverity,
  548}
  549
  550pub enum MenuInlineCompletionsPolicy {
  551    Never,
  552    ByProvider,
  553}
  554
  555pub enum EditPredictionPreview {
  556    /// Modifier is not pressed
  557    Inactive { released_too_fast: bool },
  558    /// Modifier pressed
  559    Active {
  560        since: Instant,
  561        previous_scroll_position: Option<ScrollAnchor>,
  562    },
  563}
  564
  565impl EditPredictionPreview {
  566    pub fn released_too_fast(&self) -> bool {
  567        match self {
  568            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  569            EditPredictionPreview::Active { .. } => false,
  570        }
  571    }
  572
  573    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  574        if let EditPredictionPreview::Active {
  575            previous_scroll_position,
  576            ..
  577        } = self
  578        {
  579            *previous_scroll_position = scroll_position;
  580        }
  581    }
  582}
  583
  584pub struct ContextMenuOptions {
  585    pub min_entries_visible: usize,
  586    pub max_entries_visible: usize,
  587    pub placement: Option<ContextMenuPlacement>,
  588}
  589
  590#[derive(Debug, Clone, PartialEq, Eq)]
  591pub enum ContextMenuPlacement {
  592    Above,
  593    Below,
  594}
  595
  596#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  597struct EditorActionId(usize);
  598
  599impl EditorActionId {
  600    pub fn post_inc(&mut self) -> Self {
  601        let answer = self.0;
  602
  603        *self = Self(answer + 1);
  604
  605        Self(answer)
  606    }
  607}
  608
  609// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  610// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  611
  612type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  613type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  614
  615#[derive(Default)]
  616struct ScrollbarMarkerState {
  617    scrollbar_size: Size<Pixels>,
  618    dirty: bool,
  619    markers: Arc<[PaintQuad]>,
  620    pending_refresh: Option<Task<Result<()>>>,
  621}
  622
  623impl ScrollbarMarkerState {
  624    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  625        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  626    }
  627}
  628
  629#[derive(Clone, Debug)]
  630struct RunnableTasks {
  631    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  632    offset: multi_buffer::Anchor,
  633    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  634    column: u32,
  635    // Values of all named captures, including those starting with '_'
  636    extra_variables: HashMap<String, String>,
  637    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  638    context_range: Range<BufferOffset>,
  639}
  640
  641impl RunnableTasks {
  642    fn resolve<'a>(
  643        &'a self,
  644        cx: &'a task::TaskContext,
  645    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  646        self.templates.iter().filter_map(|(kind, template)| {
  647            template
  648                .resolve_task(&kind.to_id_base(), cx)
  649                .map(|task| (kind.clone(), task))
  650        })
  651    }
  652}
  653
  654#[derive(Clone)]
  655struct ResolvedTasks {
  656    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  657    position: Anchor,
  658}
  659
  660#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  661struct BufferOffset(usize);
  662
  663// Addons allow storing per-editor state in other crates (e.g. Vim)
  664pub trait Addon: 'static {
  665    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  666
  667    fn render_buffer_header_controls(
  668        &self,
  669        _: &ExcerptInfo,
  670        _: &Window,
  671        _: &App,
  672    ) -> Option<AnyElement> {
  673        None
  674    }
  675
  676    fn to_any(&self) -> &dyn std::any::Any;
  677}
  678
  679/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  680///
  681/// See the [module level documentation](self) for more information.
  682pub struct Editor {
  683    focus_handle: FocusHandle,
  684    last_focused_descendant: Option<WeakFocusHandle>,
  685    /// The text buffer being edited
  686    buffer: Entity<MultiBuffer>,
  687    /// Map of how text in the buffer should be displayed.
  688    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  689    pub display_map: Entity<DisplayMap>,
  690    pub selections: SelectionsCollection,
  691    pub scroll_manager: ScrollManager,
  692    /// When inline assist editors are linked, they all render cursors because
  693    /// typing enters text into each of them, even the ones that aren't focused.
  694    pub(crate) show_cursor_when_unfocused: bool,
  695    columnar_selection_tail: Option<Anchor>,
  696    add_selections_state: Option<AddSelectionsState>,
  697    select_next_state: Option<SelectNextState>,
  698    select_prev_state: Option<SelectNextState>,
  699    selection_history: SelectionHistory,
  700    autoclose_regions: Vec<AutocloseRegion>,
  701    snippet_stack: InvalidationStack<SnippetState>,
  702    select_syntax_node_history: SelectSyntaxNodeHistory,
  703    ime_transaction: Option<TransactionId>,
  704    active_diagnostics: Option<ActiveDiagnosticGroup>,
  705    show_inline_diagnostics: bool,
  706    inline_diagnostics_update: Task<()>,
  707    inline_diagnostics_enabled: bool,
  708    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  709    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  710    hard_wrap: Option<usize>,
  711
  712    // TODO: make this a access method
  713    pub project: Option<Entity<Project>>,
  714    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  715    completion_provider: Option<Box<dyn CompletionProvider>>,
  716    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  717    blink_manager: Entity<BlinkManager>,
  718    show_cursor_names: bool,
  719    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  720    pub show_local_selections: bool,
  721    mode: EditorMode,
  722    show_breadcrumbs: bool,
  723    show_gutter: bool,
  724    show_scrollbars: bool,
  725    show_line_numbers: Option<bool>,
  726    use_relative_line_numbers: Option<bool>,
  727    show_git_diff_gutter: Option<bool>,
  728    show_code_actions: Option<bool>,
  729    show_runnables: Option<bool>,
  730    show_breakpoints: Option<bool>,
  731    show_wrap_guides: Option<bool>,
  732    show_indent_guides: Option<bool>,
  733    placeholder_text: Option<Arc<str>>,
  734    highlight_order: usize,
  735    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  736    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  737    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  738    scrollbar_marker_state: ScrollbarMarkerState,
  739    active_indent_guides_state: ActiveIndentGuidesState,
  740    nav_history: Option<ItemNavHistory>,
  741    context_menu: RefCell<Option<CodeContextMenu>>,
  742    context_menu_options: Option<ContextMenuOptions>,
  743    mouse_context_menu: Option<MouseContextMenu>,
  744    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  745    signature_help_state: SignatureHelpState,
  746    auto_signature_help: Option<bool>,
  747    find_all_references_task_sources: Vec<Anchor>,
  748    next_completion_id: CompletionId,
  749    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  750    code_actions_task: Option<Task<Result<()>>>,
  751    selection_highlight_task: Option<Task<()>>,
  752    document_highlights_task: Option<Task<()>>,
  753    linked_editing_range_task: Option<Task<Option<()>>>,
  754    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  755    pending_rename: Option<RenameState>,
  756    searchable: bool,
  757    cursor_shape: CursorShape,
  758    current_line_highlight: Option<CurrentLineHighlight>,
  759    collapse_matches: bool,
  760    autoindent_mode: Option<AutoindentMode>,
  761    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  762    input_enabled: bool,
  763    use_modal_editing: bool,
  764    read_only: bool,
  765    leader_peer_id: Option<PeerId>,
  766    remote_id: Option<ViewId>,
  767    hover_state: HoverState,
  768    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  769    gutter_hovered: bool,
  770    hovered_link_state: Option<HoveredLinkState>,
  771    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  772    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  773    active_inline_completion: Option<InlineCompletionState>,
  774    /// Used to prevent flickering as the user types while the menu is open
  775    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  776    edit_prediction_settings: EditPredictionSettings,
  777    inline_completions_hidden_for_vim_mode: bool,
  778    show_inline_completions_override: Option<bool>,
  779    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  780    edit_prediction_preview: EditPredictionPreview,
  781    edit_prediction_indent_conflict: bool,
  782    edit_prediction_requires_modifier_in_indent_conflict: bool,
  783    inlay_hint_cache: InlayHintCache,
  784    next_inlay_id: usize,
  785    _subscriptions: Vec<Subscription>,
  786    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  787    gutter_dimensions: GutterDimensions,
  788    style: Option<EditorStyle>,
  789    text_style_refinement: Option<TextStyleRefinement>,
  790    next_editor_action_id: EditorActionId,
  791    editor_actions:
  792        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  793    use_autoclose: bool,
  794    use_auto_surround: bool,
  795    auto_replace_emoji_shortcode: bool,
  796    jsx_tag_auto_close_enabled_in_any_buffer: bool,
  797    show_git_blame_gutter: bool,
  798    show_git_blame_inline: bool,
  799    show_git_blame_inline_delay_task: Option<Task<()>>,
  800    pub git_blame_inline_tooltip: Option<AnyWeakEntity>,
  801    git_blame_inline_enabled: bool,
  802    render_diff_hunk_controls: RenderDiffHunkControlsFn,
  803    serialize_dirty_buffers: bool,
  804    show_selection_menu: Option<bool>,
  805    blame: Option<Entity<GitBlame>>,
  806    blame_subscription: Option<Subscription>,
  807    custom_context_menu: Option<
  808        Box<
  809            dyn 'static
  810                + Fn(
  811                    &mut Self,
  812                    DisplayPoint,
  813                    &mut Window,
  814                    &mut Context<Self>,
  815                ) -> Option<Entity<ui::ContextMenu>>,
  816        >,
  817    >,
  818    last_bounds: Option<Bounds<Pixels>>,
  819    last_position_map: Option<Rc<PositionMap>>,
  820    expect_bounds_change: Option<Bounds<Pixels>>,
  821    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  822    tasks_update_task: Option<Task<()>>,
  823    breakpoint_store: Option<Entity<BreakpointStore>>,
  824    /// Allow's a user to create a breakpoint by selecting this indicator
  825    /// It should be None while a user is not hovering over the gutter
  826    /// Otherwise it represents the point that the breakpoint will be shown
  827    gutter_breakpoint_indicator: (Option<(DisplayPoint, bool)>, Option<Task<()>>),
  828    in_project_search: bool,
  829    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  830    breadcrumb_header: Option<String>,
  831    focused_block: Option<FocusedBlock>,
  832    next_scroll_position: NextScrollCursorCenterTopBottom,
  833    addons: HashMap<TypeId, Box<dyn Addon>>,
  834    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
  835    load_diff_task: Option<Shared<Task<()>>>,
  836    selection_mark_mode: bool,
  837    toggle_fold_multiple_buffers: Task<()>,
  838    _scroll_cursor_center_top_bottom_task: Task<()>,
  839    serialize_selections: Task<()>,
  840    serialize_folds: Task<()>,
  841    mouse_cursor_hidden: bool,
  842    hide_mouse_mode: HideMouseMode,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  846enum NextScrollCursorCenterTopBottom {
  847    #[default]
  848    Center,
  849    Top,
  850    Bottom,
  851}
  852
  853impl NextScrollCursorCenterTopBottom {
  854    fn next(&self) -> Self {
  855        match self {
  856            Self::Center => Self::Top,
  857            Self::Top => Self::Bottom,
  858            Self::Bottom => Self::Center,
  859        }
  860    }
  861}
  862
  863#[derive(Clone)]
  864pub struct EditorSnapshot {
  865    pub mode: EditorMode,
  866    show_gutter: bool,
  867    show_line_numbers: Option<bool>,
  868    show_git_diff_gutter: Option<bool>,
  869    show_code_actions: Option<bool>,
  870    show_runnables: Option<bool>,
  871    show_breakpoints: Option<bool>,
  872    git_blame_gutter_max_author_length: Option<usize>,
  873    pub display_snapshot: DisplaySnapshot,
  874    pub placeholder_text: Option<Arc<str>>,
  875    is_focused: bool,
  876    scroll_anchor: ScrollAnchor,
  877    ongoing_scroll: OngoingScroll,
  878    current_line_highlight: CurrentLineHighlight,
  879    gutter_hovered: bool,
  880}
  881
  882#[derive(Default, Debug, Clone, Copy)]
  883pub struct GutterDimensions {
  884    pub left_padding: Pixels,
  885    pub right_padding: Pixels,
  886    pub width: Pixels,
  887    pub margin: Pixels,
  888    pub git_blame_entries_width: Option<Pixels>,
  889}
  890
  891impl GutterDimensions {
  892    /// The full width of the space taken up by the gutter.
  893    pub fn full_width(&self) -> Pixels {
  894        self.margin + self.width
  895    }
  896
  897    /// The width of the space reserved for the fold indicators,
  898    /// use alongside 'justify_end' and `gutter_width` to
  899    /// right align content with the line numbers
  900    pub fn fold_area_width(&self) -> Pixels {
  901        self.margin + self.right_padding
  902    }
  903}
  904
  905#[derive(Debug)]
  906pub struct RemoteSelection {
  907    pub replica_id: ReplicaId,
  908    pub selection: Selection<Anchor>,
  909    pub cursor_shape: CursorShape,
  910    pub peer_id: PeerId,
  911    pub line_mode: bool,
  912    pub participant_index: Option<ParticipantIndex>,
  913    pub user_name: Option<SharedString>,
  914}
  915
  916#[derive(Clone, Debug)]
  917struct SelectionHistoryEntry {
  918    selections: Arc<[Selection<Anchor>]>,
  919    select_next_state: Option<SelectNextState>,
  920    select_prev_state: Option<SelectNextState>,
  921    add_selections_state: Option<AddSelectionsState>,
  922}
  923
  924enum SelectionHistoryMode {
  925    Normal,
  926    Undoing,
  927    Redoing,
  928}
  929
  930#[derive(Clone, PartialEq, Eq, Hash)]
  931struct HoveredCursor {
  932    replica_id: u16,
  933    selection_id: usize,
  934}
  935
  936impl Default for SelectionHistoryMode {
  937    fn default() -> Self {
  938        Self::Normal
  939    }
  940}
  941
  942#[derive(Default)]
  943struct SelectionHistory {
  944    #[allow(clippy::type_complexity)]
  945    selections_by_transaction:
  946        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  947    mode: SelectionHistoryMode,
  948    undo_stack: VecDeque<SelectionHistoryEntry>,
  949    redo_stack: VecDeque<SelectionHistoryEntry>,
  950}
  951
  952impl SelectionHistory {
  953    fn insert_transaction(
  954        &mut self,
  955        transaction_id: TransactionId,
  956        selections: Arc<[Selection<Anchor>]>,
  957    ) {
  958        self.selections_by_transaction
  959            .insert(transaction_id, (selections, None));
  960    }
  961
  962    #[allow(clippy::type_complexity)]
  963    fn transaction(
  964        &self,
  965        transaction_id: TransactionId,
  966    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  967        self.selections_by_transaction.get(&transaction_id)
  968    }
  969
  970    #[allow(clippy::type_complexity)]
  971    fn transaction_mut(
  972        &mut self,
  973        transaction_id: TransactionId,
  974    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  975        self.selections_by_transaction.get_mut(&transaction_id)
  976    }
  977
  978    fn push(&mut self, entry: SelectionHistoryEntry) {
  979        if !entry.selections.is_empty() {
  980            match self.mode {
  981                SelectionHistoryMode::Normal => {
  982                    self.push_undo(entry);
  983                    self.redo_stack.clear();
  984                }
  985                SelectionHistoryMode::Undoing => self.push_redo(entry),
  986                SelectionHistoryMode::Redoing => self.push_undo(entry),
  987            }
  988        }
  989    }
  990
  991    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  992        if self
  993            .undo_stack
  994            .back()
  995            .map_or(true, |e| e.selections != entry.selections)
  996        {
  997            self.undo_stack.push_back(entry);
  998            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  999                self.undo_stack.pop_front();
 1000            }
 1001        }
 1002    }
 1003
 1004    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1005        if self
 1006            .redo_stack
 1007            .back()
 1008            .map_or(true, |e| e.selections != entry.selections)
 1009        {
 1010            self.redo_stack.push_back(entry);
 1011            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1012                self.redo_stack.pop_front();
 1013            }
 1014        }
 1015    }
 1016}
 1017
 1018struct RowHighlight {
 1019    index: usize,
 1020    range: Range<Anchor>,
 1021    color: Hsla,
 1022    should_autoscroll: bool,
 1023}
 1024
 1025#[derive(Clone, Debug)]
 1026struct AddSelectionsState {
 1027    above: bool,
 1028    stack: Vec<usize>,
 1029}
 1030
 1031#[derive(Clone)]
 1032struct SelectNextState {
 1033    query: AhoCorasick,
 1034    wordwise: bool,
 1035    done: bool,
 1036}
 1037
 1038impl std::fmt::Debug for SelectNextState {
 1039    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1040        f.debug_struct(std::any::type_name::<Self>())
 1041            .field("wordwise", &self.wordwise)
 1042            .field("done", &self.done)
 1043            .finish()
 1044    }
 1045}
 1046
 1047#[derive(Debug)]
 1048struct AutocloseRegion {
 1049    selection_id: usize,
 1050    range: Range<Anchor>,
 1051    pair: BracketPair,
 1052}
 1053
 1054#[derive(Debug)]
 1055struct SnippetState {
 1056    ranges: Vec<Vec<Range<Anchor>>>,
 1057    active_index: usize,
 1058    choices: Vec<Option<Vec<String>>>,
 1059}
 1060
 1061#[doc(hidden)]
 1062pub struct RenameState {
 1063    pub range: Range<Anchor>,
 1064    pub old_name: Arc<str>,
 1065    pub editor: Entity<Editor>,
 1066    block_id: CustomBlockId,
 1067}
 1068
 1069struct InvalidationStack<T>(Vec<T>);
 1070
 1071struct RegisteredInlineCompletionProvider {
 1072    provider: Arc<dyn InlineCompletionProviderHandle>,
 1073    _subscription: Subscription,
 1074}
 1075
 1076#[derive(Debug, PartialEq, Eq)]
 1077struct ActiveDiagnosticGroup {
 1078    primary_range: Range<Anchor>,
 1079    primary_message: String,
 1080    group_id: usize,
 1081    blocks: HashMap<CustomBlockId, Diagnostic>,
 1082    is_valid: bool,
 1083}
 1084
 1085#[derive(Serialize, Deserialize, Clone, Debug)]
 1086pub struct ClipboardSelection {
 1087    /// The number of bytes in this selection.
 1088    pub len: usize,
 1089    /// Whether this was a full-line selection.
 1090    pub is_entire_line: bool,
 1091    /// The indentation of the first line when this content was originally copied.
 1092    pub first_line_indent: u32,
 1093}
 1094
 1095// selections, scroll behavior, was newest selection reversed
 1096type SelectSyntaxNodeHistoryState = (
 1097    Box<[Selection<usize>]>,
 1098    SelectSyntaxNodeScrollBehavior,
 1099    bool,
 1100);
 1101
 1102#[derive(Default)]
 1103struct SelectSyntaxNodeHistory {
 1104    stack: Vec<SelectSyntaxNodeHistoryState>,
 1105    // disable temporarily to allow changing selections without losing the stack
 1106    pub disable_clearing: bool,
 1107}
 1108
 1109impl SelectSyntaxNodeHistory {
 1110    pub fn try_clear(&mut self) {
 1111        if !self.disable_clearing {
 1112            self.stack.clear();
 1113        }
 1114    }
 1115
 1116    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1117        self.stack.push(selection);
 1118    }
 1119
 1120    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1121        self.stack.pop()
 1122    }
 1123}
 1124
 1125enum SelectSyntaxNodeScrollBehavior {
 1126    CursorTop,
 1127    FitSelection,
 1128    CursorBottom,
 1129}
 1130
 1131#[derive(Debug)]
 1132pub(crate) struct NavigationData {
 1133    cursor_anchor: Anchor,
 1134    cursor_position: Point,
 1135    scroll_anchor: ScrollAnchor,
 1136    scroll_top_row: u32,
 1137}
 1138
 1139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1140pub enum GotoDefinitionKind {
 1141    Symbol,
 1142    Declaration,
 1143    Type,
 1144    Implementation,
 1145}
 1146
 1147#[derive(Debug, Clone)]
 1148enum InlayHintRefreshReason {
 1149    ModifiersChanged(bool),
 1150    Toggle(bool),
 1151    SettingsChange(InlayHintSettings),
 1152    NewLinesShown,
 1153    BufferEdited(HashSet<Arc<Language>>),
 1154    RefreshRequested,
 1155    ExcerptsRemoved(Vec<ExcerptId>),
 1156}
 1157
 1158impl InlayHintRefreshReason {
 1159    fn description(&self) -> &'static str {
 1160        match self {
 1161            Self::ModifiersChanged(_) => "modifiers changed",
 1162            Self::Toggle(_) => "toggle",
 1163            Self::SettingsChange(_) => "settings change",
 1164            Self::NewLinesShown => "new lines shown",
 1165            Self::BufferEdited(_) => "buffer edited",
 1166            Self::RefreshRequested => "refresh requested",
 1167            Self::ExcerptsRemoved(_) => "excerpts removed",
 1168        }
 1169    }
 1170}
 1171
 1172pub enum FormatTarget {
 1173    Buffers,
 1174    Ranges(Vec<Range<MultiBufferPoint>>),
 1175}
 1176
 1177pub(crate) struct FocusedBlock {
 1178    id: BlockId,
 1179    focus_handle: WeakFocusHandle,
 1180}
 1181
 1182#[derive(Clone)]
 1183enum JumpData {
 1184    MultiBufferRow {
 1185        row: MultiBufferRow,
 1186        line_offset_from_top: u32,
 1187    },
 1188    MultiBufferPoint {
 1189        excerpt_id: ExcerptId,
 1190        position: Point,
 1191        anchor: text::Anchor,
 1192        line_offset_from_top: u32,
 1193    },
 1194}
 1195
 1196pub enum MultibufferSelectionMode {
 1197    First,
 1198    All,
 1199}
 1200
 1201#[derive(Clone, Copy, Debug, Default)]
 1202pub struct RewrapOptions {
 1203    pub override_language_settings: bool,
 1204    pub preserve_existing_whitespace: bool,
 1205}
 1206
 1207impl Editor {
 1208    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1209        let buffer = cx.new(|cx| Buffer::local("", cx));
 1210        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1211        Self::new(
 1212            EditorMode::SingleLine { auto_width: false },
 1213            buffer,
 1214            None,
 1215            window,
 1216            cx,
 1217        )
 1218    }
 1219
 1220    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1221        let buffer = cx.new(|cx| Buffer::local("", cx));
 1222        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1223        Self::new(EditorMode::full(), buffer, None, window, cx)
 1224    }
 1225
 1226    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1227        let buffer = cx.new(|cx| Buffer::local("", cx));
 1228        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1229        Self::new(
 1230            EditorMode::SingleLine { auto_width: true },
 1231            buffer,
 1232            None,
 1233            window,
 1234            cx,
 1235        )
 1236    }
 1237
 1238    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1239        let buffer = cx.new(|cx| Buffer::local("", cx));
 1240        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1241        Self::new(
 1242            EditorMode::AutoHeight { max_lines },
 1243            buffer,
 1244            None,
 1245            window,
 1246            cx,
 1247        )
 1248    }
 1249
 1250    pub fn for_buffer(
 1251        buffer: Entity<Buffer>,
 1252        project: Option<Entity<Project>>,
 1253        window: &mut Window,
 1254        cx: &mut Context<Self>,
 1255    ) -> Self {
 1256        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1257        Self::new(EditorMode::full(), buffer, project, window, cx)
 1258    }
 1259
 1260    pub fn for_multibuffer(
 1261        buffer: Entity<MultiBuffer>,
 1262        project: Option<Entity<Project>>,
 1263        window: &mut Window,
 1264        cx: &mut Context<Self>,
 1265    ) -> Self {
 1266        Self::new(EditorMode::full(), buffer, project, window, cx)
 1267    }
 1268
 1269    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1270        let mut clone = Self::new(
 1271            self.mode,
 1272            self.buffer.clone(),
 1273            self.project.clone(),
 1274            window,
 1275            cx,
 1276        );
 1277        self.display_map.update(cx, |display_map, cx| {
 1278            let snapshot = display_map.snapshot(cx);
 1279            clone.display_map.update(cx, |display_map, cx| {
 1280                display_map.set_state(&snapshot, cx);
 1281            });
 1282        });
 1283        clone.folds_did_change(cx);
 1284        clone.selections.clone_state(&self.selections);
 1285        clone.scroll_manager.clone_state(&self.scroll_manager);
 1286        clone.searchable = self.searchable;
 1287        clone.read_only = self.read_only;
 1288        clone
 1289    }
 1290
 1291    pub fn new(
 1292        mode: EditorMode,
 1293        buffer: Entity<MultiBuffer>,
 1294        project: Option<Entity<Project>>,
 1295        window: &mut Window,
 1296        cx: &mut Context<Self>,
 1297    ) -> Self {
 1298        let style = window.text_style();
 1299        let font_size = style.font_size.to_pixels(window.rem_size());
 1300        let editor = cx.entity().downgrade();
 1301        let fold_placeholder = FoldPlaceholder {
 1302            constrain_width: true,
 1303            render: Arc::new(move |fold_id, fold_range, cx| {
 1304                let editor = editor.clone();
 1305                div()
 1306                    .id(fold_id)
 1307                    .bg(cx.theme().colors().ghost_element_background)
 1308                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1309                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1310                    .rounded_xs()
 1311                    .size_full()
 1312                    .cursor_pointer()
 1313                    .child("")
 1314                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1315                    .on_click(move |_, _window, cx| {
 1316                        editor
 1317                            .update(cx, |editor, cx| {
 1318                                editor.unfold_ranges(
 1319                                    &[fold_range.start..fold_range.end],
 1320                                    true,
 1321                                    false,
 1322                                    cx,
 1323                                );
 1324                                cx.stop_propagation();
 1325                            })
 1326                            .ok();
 1327                    })
 1328                    .into_any()
 1329            }),
 1330            merge_adjacent: true,
 1331            ..Default::default()
 1332        };
 1333        let display_map = cx.new(|cx| {
 1334            DisplayMap::new(
 1335                buffer.clone(),
 1336                style.font(),
 1337                font_size,
 1338                None,
 1339                FILE_HEADER_HEIGHT,
 1340                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1341                fold_placeholder,
 1342                cx,
 1343            )
 1344        });
 1345
 1346        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1347
 1348        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1349
 1350        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1351            .then(|| language_settings::SoftWrap::None);
 1352
 1353        let mut project_subscriptions = Vec::new();
 1354        if mode.is_full() {
 1355            if let Some(project) = project.as_ref() {
 1356                project_subscriptions.push(cx.subscribe_in(
 1357                    project,
 1358                    window,
 1359                    |editor, _, event, window, cx| match event {
 1360                        project::Event::RefreshCodeLens => {
 1361                            // we always query lens with actions, without storing them, always refreshing them
 1362                        }
 1363                        project::Event::RefreshInlayHints => {
 1364                            editor
 1365                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1366                        }
 1367                        project::Event::SnippetEdit(id, snippet_edits) => {
 1368                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1369                                let focus_handle = editor.focus_handle(cx);
 1370                                if focus_handle.is_focused(window) {
 1371                                    let snapshot = buffer.read(cx).snapshot();
 1372                                    for (range, snippet) in snippet_edits {
 1373                                        let editor_range =
 1374                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1375                                        editor
 1376                                            .insert_snippet(
 1377                                                &[editor_range],
 1378                                                snippet.clone(),
 1379                                                window,
 1380                                                cx,
 1381                                            )
 1382                                            .ok();
 1383                                    }
 1384                                }
 1385                            }
 1386                        }
 1387                        _ => {}
 1388                    },
 1389                ));
 1390                if let Some(task_inventory) = project
 1391                    .read(cx)
 1392                    .task_store()
 1393                    .read(cx)
 1394                    .task_inventory()
 1395                    .cloned()
 1396                {
 1397                    project_subscriptions.push(cx.observe_in(
 1398                        &task_inventory,
 1399                        window,
 1400                        |editor, _, window, cx| {
 1401                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1402                        },
 1403                    ));
 1404                };
 1405
 1406                project_subscriptions.push(cx.subscribe_in(
 1407                    &project.read(cx).breakpoint_store(),
 1408                    window,
 1409                    |editor, _, event, window, cx| match event {
 1410                        BreakpointStoreEvent::ActiveDebugLineChanged => {
 1411                            if editor.go_to_active_debug_line(window, cx) {
 1412                                cx.stop_propagation();
 1413                            }
 1414                        }
 1415                        _ => {}
 1416                    },
 1417                ));
 1418            }
 1419        }
 1420
 1421        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1422
 1423        let inlay_hint_settings =
 1424            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1425        let focus_handle = cx.focus_handle();
 1426        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1427            .detach();
 1428        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1429            .detach();
 1430        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1431            .detach();
 1432        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1433            .detach();
 1434
 1435        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1436            Some(false)
 1437        } else {
 1438            None
 1439        };
 1440
 1441        let breakpoint_store = match (mode, project.as_ref()) {
 1442            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1443            _ => None,
 1444        };
 1445
 1446        let mut code_action_providers = Vec::new();
 1447        let mut load_uncommitted_diff = None;
 1448        if let Some(project) = project.clone() {
 1449            load_uncommitted_diff = Some(
 1450                get_uncommitted_diff_for_buffer(
 1451                    &project,
 1452                    buffer.read(cx).all_buffers(),
 1453                    buffer.clone(),
 1454                    cx,
 1455                )
 1456                .shared(),
 1457            );
 1458            code_action_providers.push(Rc::new(project) as Rc<_>);
 1459        }
 1460
 1461        let mut this = Self {
 1462            focus_handle,
 1463            show_cursor_when_unfocused: false,
 1464            last_focused_descendant: None,
 1465            buffer: buffer.clone(),
 1466            display_map: display_map.clone(),
 1467            selections,
 1468            scroll_manager: ScrollManager::new(cx),
 1469            columnar_selection_tail: None,
 1470            add_selections_state: None,
 1471            select_next_state: None,
 1472            select_prev_state: None,
 1473            selection_history: Default::default(),
 1474            autoclose_regions: Default::default(),
 1475            snippet_stack: Default::default(),
 1476            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1477            ime_transaction: Default::default(),
 1478            active_diagnostics: None,
 1479            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1480            inline_diagnostics_update: Task::ready(()),
 1481            inline_diagnostics: Vec::new(),
 1482            soft_wrap_mode_override,
 1483            hard_wrap: None,
 1484            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1485            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1486            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1487            project,
 1488            blink_manager: blink_manager.clone(),
 1489            show_local_selections: true,
 1490            show_scrollbars: true,
 1491            mode,
 1492            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1493            show_gutter: mode.is_full(),
 1494            show_line_numbers: None,
 1495            use_relative_line_numbers: None,
 1496            show_git_diff_gutter: None,
 1497            show_code_actions: None,
 1498            show_runnables: None,
 1499            show_breakpoints: None,
 1500            show_wrap_guides: None,
 1501            show_indent_guides,
 1502            placeholder_text: None,
 1503            highlight_order: 0,
 1504            highlighted_rows: HashMap::default(),
 1505            background_highlights: Default::default(),
 1506            gutter_highlights: TreeMap::default(),
 1507            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1508            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1509            nav_history: None,
 1510            context_menu: RefCell::new(None),
 1511            context_menu_options: None,
 1512            mouse_context_menu: None,
 1513            completion_tasks: Default::default(),
 1514            signature_help_state: SignatureHelpState::default(),
 1515            auto_signature_help: None,
 1516            find_all_references_task_sources: Vec::new(),
 1517            next_completion_id: 0,
 1518            next_inlay_id: 0,
 1519            code_action_providers,
 1520            available_code_actions: Default::default(),
 1521            code_actions_task: Default::default(),
 1522            selection_highlight_task: Default::default(),
 1523            document_highlights_task: Default::default(),
 1524            linked_editing_range_task: Default::default(),
 1525            pending_rename: Default::default(),
 1526            searchable: true,
 1527            cursor_shape: EditorSettings::get_global(cx)
 1528                .cursor_shape
 1529                .unwrap_or_default(),
 1530            current_line_highlight: None,
 1531            autoindent_mode: Some(AutoindentMode::EachLine),
 1532            collapse_matches: false,
 1533            workspace: None,
 1534            input_enabled: true,
 1535            use_modal_editing: mode.is_full(),
 1536            read_only: false,
 1537            use_autoclose: true,
 1538            use_auto_surround: true,
 1539            auto_replace_emoji_shortcode: false,
 1540            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1541            leader_peer_id: None,
 1542            remote_id: None,
 1543            hover_state: Default::default(),
 1544            pending_mouse_down: None,
 1545            hovered_link_state: Default::default(),
 1546            edit_prediction_provider: None,
 1547            active_inline_completion: None,
 1548            stale_inline_completion_in_menu: None,
 1549            edit_prediction_preview: EditPredictionPreview::Inactive {
 1550                released_too_fast: false,
 1551            },
 1552            inline_diagnostics_enabled: mode.is_full(),
 1553            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1554
 1555            gutter_hovered: false,
 1556            pixel_position_of_newest_cursor: None,
 1557            last_bounds: None,
 1558            last_position_map: None,
 1559            expect_bounds_change: None,
 1560            gutter_dimensions: GutterDimensions::default(),
 1561            style: None,
 1562            show_cursor_names: false,
 1563            hovered_cursors: Default::default(),
 1564            next_editor_action_id: EditorActionId::default(),
 1565            editor_actions: Rc::default(),
 1566            inline_completions_hidden_for_vim_mode: false,
 1567            show_inline_completions_override: None,
 1568            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1569            edit_prediction_settings: EditPredictionSettings::Disabled,
 1570            edit_prediction_indent_conflict: false,
 1571            edit_prediction_requires_modifier_in_indent_conflict: true,
 1572            custom_context_menu: None,
 1573            show_git_blame_gutter: false,
 1574            show_git_blame_inline: false,
 1575            show_selection_menu: None,
 1576            show_git_blame_inline_delay_task: None,
 1577            git_blame_inline_tooltip: None,
 1578            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1579            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1580            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1581                .session
 1582                .restore_unsaved_buffers,
 1583            blame: None,
 1584            blame_subscription: None,
 1585            tasks: Default::default(),
 1586
 1587            breakpoint_store,
 1588            gutter_breakpoint_indicator: (None, None),
 1589            _subscriptions: vec![
 1590                cx.observe(&buffer, Self::on_buffer_changed),
 1591                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1592                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1593                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1594                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1595                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1596                cx.observe_window_activation(window, |editor, window, cx| {
 1597                    let active = window.is_window_active();
 1598                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1599                        if active {
 1600                            blink_manager.enable(cx);
 1601                        } else {
 1602                            blink_manager.disable(cx);
 1603                        }
 1604                    });
 1605                }),
 1606            ],
 1607            tasks_update_task: None,
 1608            linked_edit_ranges: Default::default(),
 1609            in_project_search: false,
 1610            previous_search_ranges: None,
 1611            breadcrumb_header: None,
 1612            focused_block: None,
 1613            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1614            addons: HashMap::default(),
 1615            registered_buffers: HashMap::default(),
 1616            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1617            selection_mark_mode: false,
 1618            toggle_fold_multiple_buffers: Task::ready(()),
 1619            serialize_selections: Task::ready(()),
 1620            serialize_folds: Task::ready(()),
 1621            text_style_refinement: None,
 1622            load_diff_task: load_uncommitted_diff,
 1623            mouse_cursor_hidden: false,
 1624            hide_mouse_mode: EditorSettings::get_global(cx)
 1625                .hide_mouse
 1626                .unwrap_or_default(),
 1627        };
 1628        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1629            this._subscriptions
 1630                .push(cx.observe(breakpoints, |_, _, cx| {
 1631                    cx.notify();
 1632                }));
 1633        }
 1634        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1635        this._subscriptions.extend(project_subscriptions);
 1636
 1637        this._subscriptions.push(cx.subscribe_in(
 1638            &cx.entity(),
 1639            window,
 1640            |editor, _, e: &EditorEvent, window, cx| {
 1641                if let EditorEvent::SelectionsChanged { local } = e {
 1642                    if *local {
 1643                        let new_anchor = editor.scroll_manager.anchor();
 1644                        let snapshot = editor.snapshot(window, cx);
 1645                        editor.update_restoration_data(cx, move |data| {
 1646                            data.scroll_position = (
 1647                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1648                                new_anchor.offset,
 1649                            );
 1650                        });
 1651                    }
 1652                }
 1653            },
 1654        ));
 1655
 1656        this.end_selection(window, cx);
 1657        this.scroll_manager.show_scrollbars(window, cx);
 1658        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1659
 1660        if mode.is_full() {
 1661            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1662            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1663
 1664            if this.git_blame_inline_enabled {
 1665                this.git_blame_inline_enabled = true;
 1666                this.start_git_blame_inline(false, window, cx);
 1667            }
 1668
 1669            this.go_to_active_debug_line(window, cx);
 1670
 1671            if let Some(buffer) = buffer.read(cx).as_singleton() {
 1672                if let Some(project) = this.project.as_ref() {
 1673                    let handle = project.update(cx, |project, cx| {
 1674                        project.register_buffer_with_language_servers(&buffer, cx)
 1675                    });
 1676                    this.registered_buffers
 1677                        .insert(buffer.read(cx).remote_id(), handle);
 1678                }
 1679            }
 1680        }
 1681
 1682        this.report_editor_event("Editor Opened", None, cx);
 1683        this
 1684    }
 1685
 1686    pub fn deploy_mouse_context_menu(
 1687        &mut self,
 1688        position: gpui::Point<Pixels>,
 1689        context_menu: Entity<ContextMenu>,
 1690        window: &mut Window,
 1691        cx: &mut Context<Self>,
 1692    ) {
 1693        self.mouse_context_menu = Some(MouseContextMenu::new(
 1694            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 1695            context_menu,
 1696            None,
 1697            window,
 1698            cx,
 1699        ));
 1700    }
 1701
 1702    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 1703        self.mouse_context_menu
 1704            .as_ref()
 1705            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 1706    }
 1707
 1708    fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 1709        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 1710    }
 1711
 1712    fn key_context_internal(
 1713        &self,
 1714        has_active_edit_prediction: bool,
 1715        window: &Window,
 1716        cx: &App,
 1717    ) -> KeyContext {
 1718        let mut key_context = KeyContext::new_with_defaults();
 1719        key_context.add("Editor");
 1720        let mode = match self.mode {
 1721            EditorMode::SingleLine { .. } => "single_line",
 1722            EditorMode::AutoHeight { .. } => "auto_height",
 1723            EditorMode::Full { .. } => "full",
 1724        };
 1725
 1726        if EditorSettings::jupyter_enabled(cx) {
 1727            key_context.add("jupyter");
 1728        }
 1729
 1730        key_context.set("mode", mode);
 1731        if self.pending_rename.is_some() {
 1732            key_context.add("renaming");
 1733        }
 1734
 1735        match self.context_menu.borrow().as_ref() {
 1736            Some(CodeContextMenu::Completions(_)) => {
 1737                key_context.add("menu");
 1738                key_context.add("showing_completions");
 1739            }
 1740            Some(CodeContextMenu::CodeActions(_)) => {
 1741                key_context.add("menu");
 1742                key_context.add("showing_code_actions")
 1743            }
 1744            None => {}
 1745        }
 1746
 1747        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 1748        if !self.focus_handle(cx).contains_focused(window, cx)
 1749            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 1750        {
 1751            for addon in self.addons.values() {
 1752                addon.extend_key_context(&mut key_context, cx)
 1753            }
 1754        }
 1755
 1756        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 1757            if let Some(extension) = singleton_buffer
 1758                .read(cx)
 1759                .file()
 1760                .and_then(|file| file.path().extension()?.to_str())
 1761            {
 1762                key_context.set("extension", extension.to_string());
 1763            }
 1764        } else {
 1765            key_context.add("multibuffer");
 1766        }
 1767
 1768        if has_active_edit_prediction {
 1769            if self.edit_prediction_in_conflict() {
 1770                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 1771            } else {
 1772                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 1773                key_context.add("copilot_suggestion");
 1774            }
 1775        }
 1776
 1777        if self.selection_mark_mode {
 1778            key_context.add("selection_mode");
 1779        }
 1780
 1781        key_context
 1782    }
 1783
 1784    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 1785        self.mouse_cursor_hidden = match origin {
 1786            HideMouseCursorOrigin::TypingAction => {
 1787                matches!(
 1788                    self.hide_mouse_mode,
 1789                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 1790                )
 1791            }
 1792            HideMouseCursorOrigin::MovementAction => {
 1793                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 1794            }
 1795        };
 1796    }
 1797
 1798    pub fn edit_prediction_in_conflict(&self) -> bool {
 1799        if !self.show_edit_predictions_in_menu() {
 1800            return false;
 1801        }
 1802
 1803        let showing_completions = self
 1804            .context_menu
 1805            .borrow()
 1806            .as_ref()
 1807            .map_or(false, |context| {
 1808                matches!(context, CodeContextMenu::Completions(_))
 1809            });
 1810
 1811        showing_completions
 1812            || self.edit_prediction_requires_modifier()
 1813            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 1814            // bindings to insert tab characters.
 1815            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 1816    }
 1817
 1818    pub fn accept_edit_prediction_keybind(
 1819        &self,
 1820        window: &Window,
 1821        cx: &App,
 1822    ) -> AcceptEditPredictionBinding {
 1823        let key_context = self.key_context_internal(true, window, cx);
 1824        let in_conflict = self.edit_prediction_in_conflict();
 1825
 1826        AcceptEditPredictionBinding(
 1827            window
 1828                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 1829                .into_iter()
 1830                .filter(|binding| {
 1831                    !in_conflict
 1832                        || binding
 1833                            .keystrokes()
 1834                            .first()
 1835                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 1836                })
 1837                .rev()
 1838                .min_by_key(|binding| {
 1839                    binding
 1840                        .keystrokes()
 1841                        .first()
 1842                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 1843                }),
 1844        )
 1845    }
 1846
 1847    pub fn new_file(
 1848        workspace: &mut Workspace,
 1849        _: &workspace::NewFile,
 1850        window: &mut Window,
 1851        cx: &mut Context<Workspace>,
 1852    ) {
 1853        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 1854            "Failed to create buffer",
 1855            window,
 1856            cx,
 1857            |e, _, _| match e.error_code() {
 1858                ErrorCode::RemoteUpgradeRequired => Some(format!(
 1859                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1860                e.error_tag("required").unwrap_or("the latest version")
 1861            )),
 1862                _ => None,
 1863            },
 1864        );
 1865    }
 1866
 1867    pub fn new_in_workspace(
 1868        workspace: &mut Workspace,
 1869        window: &mut Window,
 1870        cx: &mut Context<Workspace>,
 1871    ) -> Task<Result<Entity<Editor>>> {
 1872        let project = workspace.project().clone();
 1873        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1874
 1875        cx.spawn_in(window, async move |workspace, cx| {
 1876            let buffer = create.await?;
 1877            workspace.update_in(cx, |workspace, window, cx| {
 1878                let editor =
 1879                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 1880                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 1881                editor
 1882            })
 1883        })
 1884    }
 1885
 1886    fn new_file_vertical(
 1887        workspace: &mut Workspace,
 1888        _: &workspace::NewFileSplitVertical,
 1889        window: &mut Window,
 1890        cx: &mut Context<Workspace>,
 1891    ) {
 1892        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 1893    }
 1894
 1895    fn new_file_horizontal(
 1896        workspace: &mut Workspace,
 1897        _: &workspace::NewFileSplitHorizontal,
 1898        window: &mut Window,
 1899        cx: &mut Context<Workspace>,
 1900    ) {
 1901        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 1902    }
 1903
 1904    fn new_file_in_direction(
 1905        workspace: &mut Workspace,
 1906        direction: SplitDirection,
 1907        window: &mut Window,
 1908        cx: &mut Context<Workspace>,
 1909    ) {
 1910        let project = workspace.project().clone();
 1911        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1912
 1913        cx.spawn_in(window, async move |workspace, cx| {
 1914            let buffer = create.await?;
 1915            workspace.update_in(cx, move |workspace, window, cx| {
 1916                workspace.split_item(
 1917                    direction,
 1918                    Box::new(
 1919                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 1920                    ),
 1921                    window,
 1922                    cx,
 1923                )
 1924            })?;
 1925            anyhow::Ok(())
 1926        })
 1927        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 1928            match e.error_code() {
 1929                ErrorCode::RemoteUpgradeRequired => Some(format!(
 1930                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1931                e.error_tag("required").unwrap_or("the latest version")
 1932            )),
 1933                _ => None,
 1934            }
 1935        });
 1936    }
 1937
 1938    pub fn leader_peer_id(&self) -> Option<PeerId> {
 1939        self.leader_peer_id
 1940    }
 1941
 1942    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 1943        &self.buffer
 1944    }
 1945
 1946    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 1947        self.workspace.as_ref()?.0.upgrade()
 1948    }
 1949
 1950    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 1951        self.buffer().read(cx).title(cx)
 1952    }
 1953
 1954    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 1955        let git_blame_gutter_max_author_length = self
 1956            .render_git_blame_gutter(cx)
 1957            .then(|| {
 1958                if let Some(blame) = self.blame.as_ref() {
 1959                    let max_author_length =
 1960                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 1961                    Some(max_author_length)
 1962                } else {
 1963                    None
 1964                }
 1965            })
 1966            .flatten();
 1967
 1968        EditorSnapshot {
 1969            mode: self.mode,
 1970            show_gutter: self.show_gutter,
 1971            show_line_numbers: self.show_line_numbers,
 1972            show_git_diff_gutter: self.show_git_diff_gutter,
 1973            show_code_actions: self.show_code_actions,
 1974            show_runnables: self.show_runnables,
 1975            show_breakpoints: self.show_breakpoints,
 1976            git_blame_gutter_max_author_length,
 1977            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1978            scroll_anchor: self.scroll_manager.anchor(),
 1979            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 1980            placeholder_text: self.placeholder_text.clone(),
 1981            is_focused: self.focus_handle.is_focused(window),
 1982            current_line_highlight: self
 1983                .current_line_highlight
 1984                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 1985            gutter_hovered: self.gutter_hovered,
 1986        }
 1987    }
 1988
 1989    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 1990        self.buffer.read(cx).language_at(point, cx)
 1991    }
 1992
 1993    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 1994        self.buffer.read(cx).read(cx).file_at(point).cloned()
 1995    }
 1996
 1997    pub fn active_excerpt(
 1998        &self,
 1999        cx: &App,
 2000    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2001        self.buffer
 2002            .read(cx)
 2003            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2004    }
 2005
 2006    pub fn mode(&self) -> EditorMode {
 2007        self.mode
 2008    }
 2009
 2010    pub fn set_mode(&mut self, mode: EditorMode) {
 2011        self.mode = mode;
 2012    }
 2013
 2014    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2015        self.collaboration_hub.as_deref()
 2016    }
 2017
 2018    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2019        self.collaboration_hub = Some(hub);
 2020    }
 2021
 2022    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2023        self.in_project_search = in_project_search;
 2024    }
 2025
 2026    pub fn set_custom_context_menu(
 2027        &mut self,
 2028        f: impl 'static
 2029        + Fn(
 2030            &mut Self,
 2031            DisplayPoint,
 2032            &mut Window,
 2033            &mut Context<Self>,
 2034        ) -> Option<Entity<ui::ContextMenu>>,
 2035    ) {
 2036        self.custom_context_menu = Some(Box::new(f))
 2037    }
 2038
 2039    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2040        self.completion_provider = provider;
 2041    }
 2042
 2043    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2044        self.semantics_provider.clone()
 2045    }
 2046
 2047    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2048        self.semantics_provider = provider;
 2049    }
 2050
 2051    pub fn set_edit_prediction_provider<T>(
 2052        &mut self,
 2053        provider: Option<Entity<T>>,
 2054        window: &mut Window,
 2055        cx: &mut Context<Self>,
 2056    ) where
 2057        T: EditPredictionProvider,
 2058    {
 2059        self.edit_prediction_provider =
 2060            provider.map(|provider| RegisteredInlineCompletionProvider {
 2061                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2062                    if this.focus_handle.is_focused(window) {
 2063                        this.update_visible_inline_completion(window, cx);
 2064                    }
 2065                }),
 2066                provider: Arc::new(provider),
 2067            });
 2068        self.update_edit_prediction_settings(cx);
 2069        self.refresh_inline_completion(false, false, window, cx);
 2070    }
 2071
 2072    pub fn placeholder_text(&self) -> Option<&str> {
 2073        self.placeholder_text.as_deref()
 2074    }
 2075
 2076    pub fn set_placeholder_text(
 2077        &mut self,
 2078        placeholder_text: impl Into<Arc<str>>,
 2079        cx: &mut Context<Self>,
 2080    ) {
 2081        let placeholder_text = Some(placeholder_text.into());
 2082        if self.placeholder_text != placeholder_text {
 2083            self.placeholder_text = placeholder_text;
 2084            cx.notify();
 2085        }
 2086    }
 2087
 2088    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2089        self.cursor_shape = cursor_shape;
 2090
 2091        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2092        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2093
 2094        cx.notify();
 2095    }
 2096
 2097    pub fn set_current_line_highlight(
 2098        &mut self,
 2099        current_line_highlight: Option<CurrentLineHighlight>,
 2100    ) {
 2101        self.current_line_highlight = current_line_highlight;
 2102    }
 2103
 2104    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2105        self.collapse_matches = collapse_matches;
 2106    }
 2107
 2108    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2109        let buffers = self.buffer.read(cx).all_buffers();
 2110        let Some(project) = self.project.as_ref() else {
 2111            return;
 2112        };
 2113        project.update(cx, |project, cx| {
 2114            for buffer in buffers {
 2115                self.registered_buffers
 2116                    .entry(buffer.read(cx).remote_id())
 2117                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2118            }
 2119        })
 2120    }
 2121
 2122    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2123        if self.collapse_matches {
 2124            return range.start..range.start;
 2125        }
 2126        range.clone()
 2127    }
 2128
 2129    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2130        if self.display_map.read(cx).clip_at_line_ends != clip {
 2131            self.display_map
 2132                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2133        }
 2134    }
 2135
 2136    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2137        self.input_enabled = input_enabled;
 2138    }
 2139
 2140    pub fn set_inline_completions_hidden_for_vim_mode(
 2141        &mut self,
 2142        hidden: bool,
 2143        window: &mut Window,
 2144        cx: &mut Context<Self>,
 2145    ) {
 2146        if hidden != self.inline_completions_hidden_for_vim_mode {
 2147            self.inline_completions_hidden_for_vim_mode = hidden;
 2148            if hidden {
 2149                self.update_visible_inline_completion(window, cx);
 2150            } else {
 2151                self.refresh_inline_completion(true, false, window, cx);
 2152            }
 2153        }
 2154    }
 2155
 2156    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2157        self.menu_inline_completions_policy = value;
 2158    }
 2159
 2160    pub fn set_autoindent(&mut self, autoindent: bool) {
 2161        if autoindent {
 2162            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2163        } else {
 2164            self.autoindent_mode = None;
 2165        }
 2166    }
 2167
 2168    pub fn read_only(&self, cx: &App) -> bool {
 2169        self.read_only || self.buffer.read(cx).read_only()
 2170    }
 2171
 2172    pub fn set_read_only(&mut self, read_only: bool) {
 2173        self.read_only = read_only;
 2174    }
 2175
 2176    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2177        self.use_autoclose = autoclose;
 2178    }
 2179
 2180    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2181        self.use_auto_surround = auto_surround;
 2182    }
 2183
 2184    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2185        self.auto_replace_emoji_shortcode = auto_replace;
 2186    }
 2187
 2188    pub fn toggle_edit_predictions(
 2189        &mut self,
 2190        _: &ToggleEditPrediction,
 2191        window: &mut Window,
 2192        cx: &mut Context<Self>,
 2193    ) {
 2194        if self.show_inline_completions_override.is_some() {
 2195            self.set_show_edit_predictions(None, window, cx);
 2196        } else {
 2197            let show_edit_predictions = !self.edit_predictions_enabled();
 2198            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2199        }
 2200    }
 2201
 2202    pub fn set_show_edit_predictions(
 2203        &mut self,
 2204        show_edit_predictions: Option<bool>,
 2205        window: &mut Window,
 2206        cx: &mut Context<Self>,
 2207    ) {
 2208        self.show_inline_completions_override = show_edit_predictions;
 2209        self.update_edit_prediction_settings(cx);
 2210
 2211        if let Some(false) = show_edit_predictions {
 2212            self.discard_inline_completion(false, cx);
 2213        } else {
 2214            self.refresh_inline_completion(false, true, window, cx);
 2215        }
 2216    }
 2217
 2218    fn inline_completions_disabled_in_scope(
 2219        &self,
 2220        buffer: &Entity<Buffer>,
 2221        buffer_position: language::Anchor,
 2222        cx: &App,
 2223    ) -> bool {
 2224        let snapshot = buffer.read(cx).snapshot();
 2225        let settings = snapshot.settings_at(buffer_position, cx);
 2226
 2227        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2228            return false;
 2229        };
 2230
 2231        scope.override_name().map_or(false, |scope_name| {
 2232            settings
 2233                .edit_predictions_disabled_in
 2234                .iter()
 2235                .any(|s| s == scope_name)
 2236        })
 2237    }
 2238
 2239    pub fn set_use_modal_editing(&mut self, to: bool) {
 2240        self.use_modal_editing = to;
 2241    }
 2242
 2243    pub fn use_modal_editing(&self) -> bool {
 2244        self.use_modal_editing
 2245    }
 2246
 2247    fn selections_did_change(
 2248        &mut self,
 2249        local: bool,
 2250        old_cursor_position: &Anchor,
 2251        show_completions: bool,
 2252        window: &mut Window,
 2253        cx: &mut Context<Self>,
 2254    ) {
 2255        window.invalidate_character_coordinates();
 2256
 2257        // Copy selections to primary selection buffer
 2258        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2259        if local {
 2260            let selections = self.selections.all::<usize>(cx);
 2261            let buffer_handle = self.buffer.read(cx).read(cx);
 2262
 2263            let mut text = String::new();
 2264            for (index, selection) in selections.iter().enumerate() {
 2265                let text_for_selection = buffer_handle
 2266                    .text_for_range(selection.start..selection.end)
 2267                    .collect::<String>();
 2268
 2269                text.push_str(&text_for_selection);
 2270                if index != selections.len() - 1 {
 2271                    text.push('\n');
 2272                }
 2273            }
 2274
 2275            if !text.is_empty() {
 2276                cx.write_to_primary(ClipboardItem::new_string(text));
 2277            }
 2278        }
 2279
 2280        if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() {
 2281            self.buffer.update(cx, |buffer, cx| {
 2282                buffer.set_active_selections(
 2283                    &self.selections.disjoint_anchors(),
 2284                    self.selections.line_mode,
 2285                    self.cursor_shape,
 2286                    cx,
 2287                )
 2288            });
 2289        }
 2290        let display_map = self
 2291            .display_map
 2292            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2293        let buffer = &display_map.buffer_snapshot;
 2294        self.add_selections_state = None;
 2295        self.select_next_state = None;
 2296        self.select_prev_state = None;
 2297        self.select_syntax_node_history.try_clear();
 2298        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2299        self.snippet_stack
 2300            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2301        self.take_rename(false, window, cx);
 2302
 2303        let new_cursor_position = self.selections.newest_anchor().head();
 2304
 2305        self.push_to_nav_history(
 2306            *old_cursor_position,
 2307            Some(new_cursor_position.to_point(buffer)),
 2308            false,
 2309            cx,
 2310        );
 2311
 2312        if local {
 2313            let new_cursor_position = self.selections.newest_anchor().head();
 2314            let mut context_menu = self.context_menu.borrow_mut();
 2315            let completion_menu = match context_menu.as_ref() {
 2316                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2317                _ => {
 2318                    *context_menu = None;
 2319                    None
 2320                }
 2321            };
 2322            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2323                if !self.registered_buffers.contains_key(&buffer_id) {
 2324                    if let Some(project) = self.project.as_ref() {
 2325                        project.update(cx, |project, cx| {
 2326                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2327                                return;
 2328                            };
 2329                            self.registered_buffers.insert(
 2330                                buffer_id,
 2331                                project.register_buffer_with_language_servers(&buffer, cx),
 2332                            );
 2333                        })
 2334                    }
 2335                }
 2336            }
 2337
 2338            if let Some(completion_menu) = completion_menu {
 2339                let cursor_position = new_cursor_position.to_offset(buffer);
 2340                let (word_range, kind) =
 2341                    buffer.surrounding_word(completion_menu.initial_position, true);
 2342                if kind == Some(CharKind::Word)
 2343                    && word_range.to_inclusive().contains(&cursor_position)
 2344                {
 2345                    let mut completion_menu = completion_menu.clone();
 2346                    drop(context_menu);
 2347
 2348                    let query = Self::completion_query(buffer, cursor_position);
 2349                    cx.spawn(async move |this, cx| {
 2350                        completion_menu
 2351                            .filter(query.as_deref(), cx.background_executor().clone())
 2352                            .await;
 2353
 2354                        this.update(cx, |this, cx| {
 2355                            let mut context_menu = this.context_menu.borrow_mut();
 2356                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2357                            else {
 2358                                return;
 2359                            };
 2360
 2361                            if menu.id > completion_menu.id {
 2362                                return;
 2363                            }
 2364
 2365                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2366                            drop(context_menu);
 2367                            cx.notify();
 2368                        })
 2369                    })
 2370                    .detach();
 2371
 2372                    if show_completions {
 2373                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2374                    }
 2375                } else {
 2376                    drop(context_menu);
 2377                    self.hide_context_menu(window, cx);
 2378                }
 2379            } else {
 2380                drop(context_menu);
 2381            }
 2382
 2383            hide_hover(self, cx);
 2384
 2385            if old_cursor_position.to_display_point(&display_map).row()
 2386                != new_cursor_position.to_display_point(&display_map).row()
 2387            {
 2388                self.available_code_actions.take();
 2389            }
 2390            self.refresh_code_actions(window, cx);
 2391            self.refresh_document_highlights(cx);
 2392            self.refresh_selected_text_highlights(window, cx);
 2393            refresh_matching_bracket_highlights(self, window, cx);
 2394            self.update_visible_inline_completion(window, cx);
 2395            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2396            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2397            if self.git_blame_inline_enabled {
 2398                self.start_inline_blame_timer(window, cx);
 2399            }
 2400        }
 2401
 2402        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2403        cx.emit(EditorEvent::SelectionsChanged { local });
 2404
 2405        let selections = &self.selections.disjoint;
 2406        if selections.len() == 1 {
 2407            cx.emit(SearchEvent::ActiveMatchChanged)
 2408        }
 2409        if local {
 2410            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2411                let inmemory_selections = selections
 2412                    .iter()
 2413                    .map(|s| {
 2414                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2415                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2416                    })
 2417                    .collect();
 2418                self.update_restoration_data(cx, |data| {
 2419                    data.selections = inmemory_selections;
 2420                });
 2421
 2422                if WorkspaceSettings::get(None, cx).restore_on_startup
 2423                    != RestoreOnStartupBehavior::None
 2424                {
 2425                    if let Some(workspace_id) =
 2426                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2427                    {
 2428                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2429                        let selections = selections.clone();
 2430                        let background_executor = cx.background_executor().clone();
 2431                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2432                        self.serialize_selections = cx.background_spawn(async move {
 2433                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2434                    let db_selections = selections
 2435                        .iter()
 2436                        .map(|selection| {
 2437                            (
 2438                                selection.start.to_offset(&snapshot),
 2439                                selection.end.to_offset(&snapshot),
 2440                            )
 2441                        })
 2442                        .collect();
 2443
 2444                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2445                        .await
 2446                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2447                        .log_err();
 2448                });
 2449                    }
 2450                }
 2451            }
 2452        }
 2453
 2454        cx.notify();
 2455    }
 2456
 2457    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2458        use text::ToOffset as _;
 2459        use text::ToPoint as _;
 2460
 2461        if WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None {
 2462            return;
 2463        }
 2464
 2465        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2466            return;
 2467        };
 2468
 2469        let snapshot = singleton.read(cx).snapshot();
 2470        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2471            let display_snapshot = display_map.snapshot(cx);
 2472
 2473            display_snapshot
 2474                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2475                .map(|fold| {
 2476                    fold.range.start.text_anchor.to_point(&snapshot)
 2477                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2478                })
 2479                .collect()
 2480        });
 2481        self.update_restoration_data(cx, |data| {
 2482            data.folds = inmemory_folds;
 2483        });
 2484
 2485        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2486            return;
 2487        };
 2488        let background_executor = cx.background_executor().clone();
 2489        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2490        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2491            display_map
 2492                .snapshot(cx)
 2493                .folds_in_range(0..snapshot.len())
 2494                .map(|fold| {
 2495                    (
 2496                        fold.range.start.text_anchor.to_offset(&snapshot),
 2497                        fold.range.end.text_anchor.to_offset(&snapshot),
 2498                    )
 2499                })
 2500                .collect()
 2501        });
 2502        self.serialize_folds = cx.background_spawn(async move {
 2503            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2504            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2505                .await
 2506                .with_context(|| {
 2507                    format!(
 2508                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2509                    )
 2510                })
 2511                .log_err();
 2512        });
 2513    }
 2514
 2515    pub fn sync_selections(
 2516        &mut self,
 2517        other: Entity<Editor>,
 2518        cx: &mut Context<Self>,
 2519    ) -> gpui::Subscription {
 2520        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2521        self.selections.change_with(cx, |selections| {
 2522            selections.select_anchors(other_selections);
 2523        });
 2524
 2525        let other_subscription =
 2526            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2527                EditorEvent::SelectionsChanged { local: true } => {
 2528                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2529                    if other_selections.is_empty() {
 2530                        return;
 2531                    }
 2532                    this.selections.change_with(cx, |selections| {
 2533                        selections.select_anchors(other_selections);
 2534                    });
 2535                }
 2536                _ => {}
 2537            });
 2538
 2539        let this_subscription =
 2540            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2541                EditorEvent::SelectionsChanged { local: true } => {
 2542                    let these_selections = this.selections.disjoint.to_vec();
 2543                    if these_selections.is_empty() {
 2544                        return;
 2545                    }
 2546                    other.update(cx, |other_editor, cx| {
 2547                        other_editor.selections.change_with(cx, |selections| {
 2548                            selections.select_anchors(these_selections);
 2549                        })
 2550                    });
 2551                }
 2552                _ => {}
 2553            });
 2554
 2555        Subscription::join(other_subscription, this_subscription)
 2556    }
 2557
 2558    pub fn change_selections<R>(
 2559        &mut self,
 2560        autoscroll: Option<Autoscroll>,
 2561        window: &mut Window,
 2562        cx: &mut Context<Self>,
 2563        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2564    ) -> R {
 2565        self.change_selections_inner(autoscroll, true, window, cx, change)
 2566    }
 2567
 2568    fn change_selections_inner<R>(
 2569        &mut self,
 2570        autoscroll: Option<Autoscroll>,
 2571        request_completions: bool,
 2572        window: &mut Window,
 2573        cx: &mut Context<Self>,
 2574        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2575    ) -> R {
 2576        let old_cursor_position = self.selections.newest_anchor().head();
 2577        self.push_to_selection_history();
 2578
 2579        let (changed, result) = self.selections.change_with(cx, change);
 2580
 2581        if changed {
 2582            if let Some(autoscroll) = autoscroll {
 2583                self.request_autoscroll(autoscroll, cx);
 2584            }
 2585            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2586
 2587            if self.should_open_signature_help_automatically(
 2588                &old_cursor_position,
 2589                self.signature_help_state.backspace_pressed(),
 2590                cx,
 2591            ) {
 2592                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2593            }
 2594            self.signature_help_state.set_backspace_pressed(false);
 2595        }
 2596
 2597        result
 2598    }
 2599
 2600    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2601    where
 2602        I: IntoIterator<Item = (Range<S>, T)>,
 2603        S: ToOffset,
 2604        T: Into<Arc<str>>,
 2605    {
 2606        if self.read_only(cx) {
 2607            return;
 2608        }
 2609
 2610        self.buffer
 2611            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2612    }
 2613
 2614    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2615    where
 2616        I: IntoIterator<Item = (Range<S>, T)>,
 2617        S: ToOffset,
 2618        T: Into<Arc<str>>,
 2619    {
 2620        if self.read_only(cx) {
 2621            return;
 2622        }
 2623
 2624        self.buffer.update(cx, |buffer, cx| {
 2625            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2626        });
 2627    }
 2628
 2629    pub fn edit_with_block_indent<I, S, T>(
 2630        &mut self,
 2631        edits: I,
 2632        original_indent_columns: Vec<Option<u32>>,
 2633        cx: &mut Context<Self>,
 2634    ) where
 2635        I: IntoIterator<Item = (Range<S>, T)>,
 2636        S: ToOffset,
 2637        T: Into<Arc<str>>,
 2638    {
 2639        if self.read_only(cx) {
 2640            return;
 2641        }
 2642
 2643        self.buffer.update(cx, |buffer, cx| {
 2644            buffer.edit(
 2645                edits,
 2646                Some(AutoindentMode::Block {
 2647                    original_indent_columns,
 2648                }),
 2649                cx,
 2650            )
 2651        });
 2652    }
 2653
 2654    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2655        self.hide_context_menu(window, cx);
 2656
 2657        match phase {
 2658            SelectPhase::Begin {
 2659                position,
 2660                add,
 2661                click_count,
 2662            } => self.begin_selection(position, add, click_count, window, cx),
 2663            SelectPhase::BeginColumnar {
 2664                position,
 2665                goal_column,
 2666                reset,
 2667            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 2668            SelectPhase::Extend {
 2669                position,
 2670                click_count,
 2671            } => self.extend_selection(position, click_count, window, cx),
 2672            SelectPhase::Update {
 2673                position,
 2674                goal_column,
 2675                scroll_delta,
 2676            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 2677            SelectPhase::End => self.end_selection(window, cx),
 2678        }
 2679    }
 2680
 2681    fn extend_selection(
 2682        &mut self,
 2683        position: DisplayPoint,
 2684        click_count: usize,
 2685        window: &mut Window,
 2686        cx: &mut Context<Self>,
 2687    ) {
 2688        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2689        let tail = self.selections.newest::<usize>(cx).tail();
 2690        self.begin_selection(position, false, click_count, window, cx);
 2691
 2692        let position = position.to_offset(&display_map, Bias::Left);
 2693        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2694
 2695        let mut pending_selection = self
 2696            .selections
 2697            .pending_anchor()
 2698            .expect("extend_selection not called with pending selection");
 2699        if position >= tail {
 2700            pending_selection.start = tail_anchor;
 2701        } else {
 2702            pending_selection.end = tail_anchor;
 2703            pending_selection.reversed = true;
 2704        }
 2705
 2706        let mut pending_mode = self.selections.pending_mode().unwrap();
 2707        match &mut pending_mode {
 2708            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2709            _ => {}
 2710        }
 2711
 2712        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 2713            s.set_pending(pending_selection, pending_mode)
 2714        });
 2715    }
 2716
 2717    fn begin_selection(
 2718        &mut self,
 2719        position: DisplayPoint,
 2720        add: bool,
 2721        click_count: usize,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) {
 2725        if !self.focus_handle.is_focused(window) {
 2726            self.last_focused_descendant = None;
 2727            window.focus(&self.focus_handle);
 2728        }
 2729
 2730        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2731        let buffer = &display_map.buffer_snapshot;
 2732        let newest_selection = self.selections.newest_anchor().clone();
 2733        let position = display_map.clip_point(position, Bias::Left);
 2734
 2735        let start;
 2736        let end;
 2737        let mode;
 2738        let mut auto_scroll;
 2739        match click_count {
 2740            1 => {
 2741                start = buffer.anchor_before(position.to_point(&display_map));
 2742                end = start;
 2743                mode = SelectMode::Character;
 2744                auto_scroll = true;
 2745            }
 2746            2 => {
 2747                let range = movement::surrounding_word(&display_map, position);
 2748                start = buffer.anchor_before(range.start.to_point(&display_map));
 2749                end = buffer.anchor_before(range.end.to_point(&display_map));
 2750                mode = SelectMode::Word(start..end);
 2751                auto_scroll = true;
 2752            }
 2753            3 => {
 2754                let position = display_map
 2755                    .clip_point(position, Bias::Left)
 2756                    .to_point(&display_map);
 2757                let line_start = display_map.prev_line_boundary(position).0;
 2758                let next_line_start = buffer.clip_point(
 2759                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2760                    Bias::Left,
 2761                );
 2762                start = buffer.anchor_before(line_start);
 2763                end = buffer.anchor_before(next_line_start);
 2764                mode = SelectMode::Line(start..end);
 2765                auto_scroll = true;
 2766            }
 2767            _ => {
 2768                start = buffer.anchor_before(0);
 2769                end = buffer.anchor_before(buffer.len());
 2770                mode = SelectMode::All;
 2771                auto_scroll = false;
 2772            }
 2773        }
 2774        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 2775
 2776        let point_to_delete: Option<usize> = {
 2777            let selected_points: Vec<Selection<Point>> =
 2778                self.selections.disjoint_in_range(start..end, cx);
 2779
 2780            if !add || click_count > 1 {
 2781                None
 2782            } else if !selected_points.is_empty() {
 2783                Some(selected_points[0].id)
 2784            } else {
 2785                let clicked_point_already_selected =
 2786                    self.selections.disjoint.iter().find(|selection| {
 2787                        selection.start.to_point(buffer) == start.to_point(buffer)
 2788                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2789                    });
 2790
 2791                clicked_point_already_selected.map(|selection| selection.id)
 2792            }
 2793        };
 2794
 2795        let selections_count = self.selections.count();
 2796
 2797        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 2798            if let Some(point_to_delete) = point_to_delete {
 2799                s.delete(point_to_delete);
 2800
 2801                if selections_count == 1 {
 2802                    s.set_pending_anchor_range(start..end, mode);
 2803                }
 2804            } else {
 2805                if !add {
 2806                    s.clear_disjoint();
 2807                } else if click_count > 1 {
 2808                    s.delete(newest_selection.id)
 2809                }
 2810
 2811                s.set_pending_anchor_range(start..end, mode);
 2812            }
 2813        });
 2814    }
 2815
 2816    fn begin_columnar_selection(
 2817        &mut self,
 2818        position: DisplayPoint,
 2819        goal_column: u32,
 2820        reset: bool,
 2821        window: &mut Window,
 2822        cx: &mut Context<Self>,
 2823    ) {
 2824        if !self.focus_handle.is_focused(window) {
 2825            self.last_focused_descendant = None;
 2826            window.focus(&self.focus_handle);
 2827        }
 2828
 2829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2830
 2831        if reset {
 2832            let pointer_position = display_map
 2833                .buffer_snapshot
 2834                .anchor_before(position.to_point(&display_map));
 2835
 2836            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 2837                s.clear_disjoint();
 2838                s.set_pending_anchor_range(
 2839                    pointer_position..pointer_position,
 2840                    SelectMode::Character,
 2841                );
 2842            });
 2843        }
 2844
 2845        let tail = self.selections.newest::<Point>(cx).tail();
 2846        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2847
 2848        if !reset {
 2849            self.select_columns(
 2850                tail.to_display_point(&display_map),
 2851                position,
 2852                goal_column,
 2853                &display_map,
 2854                window,
 2855                cx,
 2856            );
 2857        }
 2858    }
 2859
 2860    fn update_selection(
 2861        &mut self,
 2862        position: DisplayPoint,
 2863        goal_column: u32,
 2864        scroll_delta: gpui::Point<f32>,
 2865        window: &mut Window,
 2866        cx: &mut Context<Self>,
 2867    ) {
 2868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2869
 2870        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2871            let tail = tail.to_display_point(&display_map);
 2872            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 2873        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2874            let buffer = self.buffer.read(cx).snapshot(cx);
 2875            let head;
 2876            let tail;
 2877            let mode = self.selections.pending_mode().unwrap();
 2878            match &mode {
 2879                SelectMode::Character => {
 2880                    head = position.to_point(&display_map);
 2881                    tail = pending.tail().to_point(&buffer);
 2882                }
 2883                SelectMode::Word(original_range) => {
 2884                    let original_display_range = original_range.start.to_display_point(&display_map)
 2885                        ..original_range.end.to_display_point(&display_map);
 2886                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2887                        ..original_display_range.end.to_point(&display_map);
 2888                    if movement::is_inside_word(&display_map, position)
 2889                        || original_display_range.contains(&position)
 2890                    {
 2891                        let word_range = movement::surrounding_word(&display_map, position);
 2892                        if word_range.start < original_display_range.start {
 2893                            head = word_range.start.to_point(&display_map);
 2894                        } else {
 2895                            head = word_range.end.to_point(&display_map);
 2896                        }
 2897                    } else {
 2898                        head = position.to_point(&display_map);
 2899                    }
 2900
 2901                    if head <= original_buffer_range.start {
 2902                        tail = original_buffer_range.end;
 2903                    } else {
 2904                        tail = original_buffer_range.start;
 2905                    }
 2906                }
 2907                SelectMode::Line(original_range) => {
 2908                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2909
 2910                    let position = display_map
 2911                        .clip_point(position, Bias::Left)
 2912                        .to_point(&display_map);
 2913                    let line_start = display_map.prev_line_boundary(position).0;
 2914                    let next_line_start = buffer.clip_point(
 2915                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2916                        Bias::Left,
 2917                    );
 2918
 2919                    if line_start < original_range.start {
 2920                        head = line_start
 2921                    } else {
 2922                        head = next_line_start
 2923                    }
 2924
 2925                    if head <= original_range.start {
 2926                        tail = original_range.end;
 2927                    } else {
 2928                        tail = original_range.start;
 2929                    }
 2930                }
 2931                SelectMode::All => {
 2932                    return;
 2933                }
 2934            };
 2935
 2936            if head < tail {
 2937                pending.start = buffer.anchor_before(head);
 2938                pending.end = buffer.anchor_before(tail);
 2939                pending.reversed = true;
 2940            } else {
 2941                pending.start = buffer.anchor_before(tail);
 2942                pending.end = buffer.anchor_before(head);
 2943                pending.reversed = false;
 2944            }
 2945
 2946            self.change_selections(None, window, cx, |s| {
 2947                s.set_pending(pending, mode);
 2948            });
 2949        } else {
 2950            log::error!("update_selection dispatched with no pending selection");
 2951            return;
 2952        }
 2953
 2954        self.apply_scroll_delta(scroll_delta, window, cx);
 2955        cx.notify();
 2956    }
 2957
 2958    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 2959        self.columnar_selection_tail.take();
 2960        if self.selections.pending_anchor().is_some() {
 2961            let selections = self.selections.all::<usize>(cx);
 2962            self.change_selections(None, window, cx, |s| {
 2963                s.select(selections);
 2964                s.clear_pending();
 2965            });
 2966        }
 2967    }
 2968
 2969    fn select_columns(
 2970        &mut self,
 2971        tail: DisplayPoint,
 2972        head: DisplayPoint,
 2973        goal_column: u32,
 2974        display_map: &DisplaySnapshot,
 2975        window: &mut Window,
 2976        cx: &mut Context<Self>,
 2977    ) {
 2978        let start_row = cmp::min(tail.row(), head.row());
 2979        let end_row = cmp::max(tail.row(), head.row());
 2980        let start_column = cmp::min(tail.column(), goal_column);
 2981        let end_column = cmp::max(tail.column(), goal_column);
 2982        let reversed = start_column < tail.column();
 2983
 2984        let selection_ranges = (start_row.0..=end_row.0)
 2985            .map(DisplayRow)
 2986            .filter_map(|row| {
 2987                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2988                    let start = display_map
 2989                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2990                        .to_point(display_map);
 2991                    let end = display_map
 2992                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2993                        .to_point(display_map);
 2994                    if reversed {
 2995                        Some(end..start)
 2996                    } else {
 2997                        Some(start..end)
 2998                    }
 2999                } else {
 3000                    None
 3001                }
 3002            })
 3003            .collect::<Vec<_>>();
 3004
 3005        self.change_selections(None, window, cx, |s| {
 3006            s.select_ranges(selection_ranges);
 3007        });
 3008        cx.notify();
 3009    }
 3010
 3011    pub fn has_pending_nonempty_selection(&self) -> bool {
 3012        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3013            Some(Selection { start, end, .. }) => start != end,
 3014            None => false,
 3015        };
 3016
 3017        pending_nonempty_selection
 3018            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3019    }
 3020
 3021    pub fn has_pending_selection(&self) -> bool {
 3022        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3023    }
 3024
 3025    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3026        self.selection_mark_mode = false;
 3027
 3028        if self.clear_expanded_diff_hunks(cx) {
 3029            cx.notify();
 3030            return;
 3031        }
 3032        if self.dismiss_menus_and_popups(true, window, cx) {
 3033            return;
 3034        }
 3035
 3036        if self.mode.is_full()
 3037            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3038        {
 3039            return;
 3040        }
 3041
 3042        cx.propagate();
 3043    }
 3044
 3045    pub fn dismiss_menus_and_popups(
 3046        &mut self,
 3047        is_user_requested: bool,
 3048        window: &mut Window,
 3049        cx: &mut Context<Self>,
 3050    ) -> bool {
 3051        if self.take_rename(false, window, cx).is_some() {
 3052            return true;
 3053        }
 3054
 3055        if hide_hover(self, cx) {
 3056            return true;
 3057        }
 3058
 3059        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3060            return true;
 3061        }
 3062
 3063        if self.hide_context_menu(window, cx).is_some() {
 3064            return true;
 3065        }
 3066
 3067        if self.mouse_context_menu.take().is_some() {
 3068            return true;
 3069        }
 3070
 3071        if is_user_requested && self.discard_inline_completion(true, cx) {
 3072            return true;
 3073        }
 3074
 3075        if self.snippet_stack.pop().is_some() {
 3076            return true;
 3077        }
 3078
 3079        if self.mode.is_full() && self.active_diagnostics.is_some() {
 3080            self.dismiss_diagnostics(cx);
 3081            return true;
 3082        }
 3083
 3084        false
 3085    }
 3086
 3087    fn linked_editing_ranges_for(
 3088        &self,
 3089        selection: Range<text::Anchor>,
 3090        cx: &App,
 3091    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3092        if self.linked_edit_ranges.is_empty() {
 3093            return None;
 3094        }
 3095        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3096            selection.end.buffer_id.and_then(|end_buffer_id| {
 3097                if selection.start.buffer_id != Some(end_buffer_id) {
 3098                    return None;
 3099                }
 3100                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3101                let snapshot = buffer.read(cx).snapshot();
 3102                self.linked_edit_ranges
 3103                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3104                    .map(|ranges| (ranges, snapshot, buffer))
 3105            })?;
 3106        use text::ToOffset as TO;
 3107        // find offset from the start of current range to current cursor position
 3108        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3109
 3110        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3111        let start_difference = start_offset - start_byte_offset;
 3112        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3113        let end_difference = end_offset - start_byte_offset;
 3114        // Current range has associated linked ranges.
 3115        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3116        for range in linked_ranges.iter() {
 3117            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3118            let end_offset = start_offset + end_difference;
 3119            let start_offset = start_offset + start_difference;
 3120            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3121                continue;
 3122            }
 3123            if self.selections.disjoint_anchor_ranges().any(|s| {
 3124                if s.start.buffer_id != selection.start.buffer_id
 3125                    || s.end.buffer_id != selection.end.buffer_id
 3126                {
 3127                    return false;
 3128                }
 3129                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3130                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3131            }) {
 3132                continue;
 3133            }
 3134            let start = buffer_snapshot.anchor_after(start_offset);
 3135            let end = buffer_snapshot.anchor_after(end_offset);
 3136            linked_edits
 3137                .entry(buffer.clone())
 3138                .or_default()
 3139                .push(start..end);
 3140        }
 3141        Some(linked_edits)
 3142    }
 3143
 3144    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3145        let text: Arc<str> = text.into();
 3146
 3147        if self.read_only(cx) {
 3148            return;
 3149        }
 3150
 3151        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3152
 3153        let selections = self.selections.all_adjusted(cx);
 3154        let mut bracket_inserted = false;
 3155        let mut edits = Vec::new();
 3156        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3157        let mut new_selections = Vec::with_capacity(selections.len());
 3158        let mut new_autoclose_regions = Vec::new();
 3159        let snapshot = self.buffer.read(cx).read(cx);
 3160        let mut clear_linked_edit_ranges = false;
 3161
 3162        for (selection, autoclose_region) in
 3163            self.selections_with_autoclose_regions(selections, &snapshot)
 3164        {
 3165            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3166                // Determine if the inserted text matches the opening or closing
 3167                // bracket of any of this language's bracket pairs.
 3168                let mut bracket_pair = None;
 3169                let mut is_bracket_pair_start = false;
 3170                let mut is_bracket_pair_end = false;
 3171                if !text.is_empty() {
 3172                    let mut bracket_pair_matching_end = None;
 3173                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3174                    //  and they are removing the character that triggered IME popup.
 3175                    for (pair, enabled) in scope.brackets() {
 3176                        if !pair.close && !pair.surround {
 3177                            continue;
 3178                        }
 3179
 3180                        if enabled && pair.start.ends_with(text.as_ref()) {
 3181                            let prefix_len = pair.start.len() - text.len();
 3182                            let preceding_text_matches_prefix = prefix_len == 0
 3183                                || (selection.start.column >= (prefix_len as u32)
 3184                                    && snapshot.contains_str_at(
 3185                                        Point::new(
 3186                                            selection.start.row,
 3187                                            selection.start.column - (prefix_len as u32),
 3188                                        ),
 3189                                        &pair.start[..prefix_len],
 3190                                    ));
 3191                            if preceding_text_matches_prefix {
 3192                                bracket_pair = Some(pair.clone());
 3193                                is_bracket_pair_start = true;
 3194                                break;
 3195                            }
 3196                        }
 3197                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3198                        {
 3199                            // take first bracket pair matching end, but don't break in case a later bracket
 3200                            // pair matches start
 3201                            bracket_pair_matching_end = Some(pair.clone());
 3202                        }
 3203                    }
 3204                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3205                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3206                        is_bracket_pair_end = true;
 3207                    }
 3208                }
 3209
 3210                if let Some(bracket_pair) = bracket_pair {
 3211                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3212                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3213                    let auto_surround =
 3214                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3215                    if selection.is_empty() {
 3216                        if is_bracket_pair_start {
 3217                            // If the inserted text is a suffix of an opening bracket and the
 3218                            // selection is preceded by the rest of the opening bracket, then
 3219                            // insert the closing bracket.
 3220                            let following_text_allows_autoclose = snapshot
 3221                                .chars_at(selection.start)
 3222                                .next()
 3223                                .map_or(true, |c| scope.should_autoclose_before(c));
 3224
 3225                            let preceding_text_allows_autoclose = selection.start.column == 0
 3226                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3227                                    true,
 3228                                    |c| {
 3229                                        bracket_pair.start != bracket_pair.end
 3230                                            || !snapshot
 3231                                                .char_classifier_at(selection.start)
 3232                                                .is_word(c)
 3233                                    },
 3234                                );
 3235
 3236                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3237                                && bracket_pair.start.len() == 1
 3238                            {
 3239                                let target = bracket_pair.start.chars().next().unwrap();
 3240                                let current_line_count = snapshot
 3241                                    .reversed_chars_at(selection.start)
 3242                                    .take_while(|&c| c != '\n')
 3243                                    .filter(|&c| c == target)
 3244                                    .count();
 3245                                current_line_count % 2 == 1
 3246                            } else {
 3247                                false
 3248                            };
 3249
 3250                            if autoclose
 3251                                && bracket_pair.close
 3252                                && following_text_allows_autoclose
 3253                                && preceding_text_allows_autoclose
 3254                                && !is_closing_quote
 3255                            {
 3256                                let anchor = snapshot.anchor_before(selection.end);
 3257                                new_selections.push((selection.map(|_| anchor), text.len()));
 3258                                new_autoclose_regions.push((
 3259                                    anchor,
 3260                                    text.len(),
 3261                                    selection.id,
 3262                                    bracket_pair.clone(),
 3263                                ));
 3264                                edits.push((
 3265                                    selection.range(),
 3266                                    format!("{}{}", text, bracket_pair.end).into(),
 3267                                ));
 3268                                bracket_inserted = true;
 3269                                continue;
 3270                            }
 3271                        }
 3272
 3273                        if let Some(region) = autoclose_region {
 3274                            // If the selection is followed by an auto-inserted closing bracket,
 3275                            // then don't insert that closing bracket again; just move the selection
 3276                            // past the closing bracket.
 3277                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3278                                && text.as_ref() == region.pair.end.as_str();
 3279                            if should_skip {
 3280                                let anchor = snapshot.anchor_after(selection.end);
 3281                                new_selections
 3282                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3283                                continue;
 3284                            }
 3285                        }
 3286
 3287                        let always_treat_brackets_as_autoclosed = snapshot
 3288                            .language_settings_at(selection.start, cx)
 3289                            .always_treat_brackets_as_autoclosed;
 3290                        if always_treat_brackets_as_autoclosed
 3291                            && is_bracket_pair_end
 3292                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3293                        {
 3294                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3295                            // and the inserted text is a closing bracket and the selection is followed
 3296                            // by the closing bracket then move the selection past the closing bracket.
 3297                            let anchor = snapshot.anchor_after(selection.end);
 3298                            new_selections.push((selection.map(|_| anchor), text.len()));
 3299                            continue;
 3300                        }
 3301                    }
 3302                    // If an opening bracket is 1 character long and is typed while
 3303                    // text is selected, then surround that text with the bracket pair.
 3304                    else if auto_surround
 3305                        && bracket_pair.surround
 3306                        && is_bracket_pair_start
 3307                        && bracket_pair.start.chars().count() == 1
 3308                    {
 3309                        edits.push((selection.start..selection.start, text.clone()));
 3310                        edits.push((
 3311                            selection.end..selection.end,
 3312                            bracket_pair.end.as_str().into(),
 3313                        ));
 3314                        bracket_inserted = true;
 3315                        new_selections.push((
 3316                            Selection {
 3317                                id: selection.id,
 3318                                start: snapshot.anchor_after(selection.start),
 3319                                end: snapshot.anchor_before(selection.end),
 3320                                reversed: selection.reversed,
 3321                                goal: selection.goal,
 3322                            },
 3323                            0,
 3324                        ));
 3325                        continue;
 3326                    }
 3327                }
 3328            }
 3329
 3330            if self.auto_replace_emoji_shortcode
 3331                && selection.is_empty()
 3332                && text.as_ref().ends_with(':')
 3333            {
 3334                if let Some(possible_emoji_short_code) =
 3335                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3336                {
 3337                    if !possible_emoji_short_code.is_empty() {
 3338                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3339                            let emoji_shortcode_start = Point::new(
 3340                                selection.start.row,
 3341                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3342                            );
 3343
 3344                            // Remove shortcode from buffer
 3345                            edits.push((
 3346                                emoji_shortcode_start..selection.start,
 3347                                "".to_string().into(),
 3348                            ));
 3349                            new_selections.push((
 3350                                Selection {
 3351                                    id: selection.id,
 3352                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3353                                    end: snapshot.anchor_before(selection.start),
 3354                                    reversed: selection.reversed,
 3355                                    goal: selection.goal,
 3356                                },
 3357                                0,
 3358                            ));
 3359
 3360                            // Insert emoji
 3361                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3362                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3363                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3364
 3365                            continue;
 3366                        }
 3367                    }
 3368                }
 3369            }
 3370
 3371            // If not handling any auto-close operation, then just replace the selected
 3372            // text with the given input and move the selection to the end of the
 3373            // newly inserted text.
 3374            let anchor = snapshot.anchor_after(selection.end);
 3375            if !self.linked_edit_ranges.is_empty() {
 3376                let start_anchor = snapshot.anchor_before(selection.start);
 3377
 3378                let is_word_char = text.chars().next().map_or(true, |char| {
 3379                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3380                    classifier.is_word(char)
 3381                });
 3382
 3383                if is_word_char {
 3384                    if let Some(ranges) = self
 3385                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3386                    {
 3387                        for (buffer, edits) in ranges {
 3388                            linked_edits
 3389                                .entry(buffer.clone())
 3390                                .or_default()
 3391                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3392                        }
 3393                    }
 3394                } else {
 3395                    clear_linked_edit_ranges = true;
 3396                }
 3397            }
 3398
 3399            new_selections.push((selection.map(|_| anchor), 0));
 3400            edits.push((selection.start..selection.end, text.clone()));
 3401        }
 3402
 3403        drop(snapshot);
 3404
 3405        self.transact(window, cx, |this, window, cx| {
 3406            if clear_linked_edit_ranges {
 3407                this.linked_edit_ranges.clear();
 3408            }
 3409            let initial_buffer_versions =
 3410                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3411
 3412            this.buffer.update(cx, |buffer, cx| {
 3413                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3414            });
 3415            for (buffer, edits) in linked_edits {
 3416                buffer.update(cx, |buffer, cx| {
 3417                    let snapshot = buffer.snapshot();
 3418                    let edits = edits
 3419                        .into_iter()
 3420                        .map(|(range, text)| {
 3421                            use text::ToPoint as TP;
 3422                            let end_point = TP::to_point(&range.end, &snapshot);
 3423                            let start_point = TP::to_point(&range.start, &snapshot);
 3424                            (start_point..end_point, text)
 3425                        })
 3426                        .sorted_by_key(|(range, _)| range.start);
 3427                    buffer.edit(edits, None, cx);
 3428                })
 3429            }
 3430            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3431            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3432            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3433            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3434                .zip(new_selection_deltas)
 3435                .map(|(selection, delta)| Selection {
 3436                    id: selection.id,
 3437                    start: selection.start + delta,
 3438                    end: selection.end + delta,
 3439                    reversed: selection.reversed,
 3440                    goal: SelectionGoal::None,
 3441                })
 3442                .collect::<Vec<_>>();
 3443
 3444            let mut i = 0;
 3445            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3446                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3447                let start = map.buffer_snapshot.anchor_before(position);
 3448                let end = map.buffer_snapshot.anchor_after(position);
 3449                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3450                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3451                        Ordering::Less => i += 1,
 3452                        Ordering::Greater => break,
 3453                        Ordering::Equal => {
 3454                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3455                                Ordering::Less => i += 1,
 3456                                Ordering::Equal => break,
 3457                                Ordering::Greater => break,
 3458                            }
 3459                        }
 3460                    }
 3461                }
 3462                this.autoclose_regions.insert(
 3463                    i,
 3464                    AutocloseRegion {
 3465                        selection_id,
 3466                        range: start..end,
 3467                        pair,
 3468                    },
 3469                );
 3470            }
 3471
 3472            let had_active_inline_completion = this.has_active_inline_completion();
 3473            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3474                s.select(new_selections)
 3475            });
 3476
 3477            if !bracket_inserted {
 3478                if let Some(on_type_format_task) =
 3479                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3480                {
 3481                    on_type_format_task.detach_and_log_err(cx);
 3482                }
 3483            }
 3484
 3485            let editor_settings = EditorSettings::get_global(cx);
 3486            if bracket_inserted
 3487                && (editor_settings.auto_signature_help
 3488                    || editor_settings.show_signature_help_after_edits)
 3489            {
 3490                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3491            }
 3492
 3493            let trigger_in_words =
 3494                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3495            if this.hard_wrap.is_some() {
 3496                let latest: Range<Point> = this.selections.newest(cx).range();
 3497                if latest.is_empty()
 3498                    && this
 3499                        .buffer()
 3500                        .read(cx)
 3501                        .snapshot(cx)
 3502                        .line_len(MultiBufferRow(latest.start.row))
 3503                        == latest.start.column
 3504                {
 3505                    this.rewrap_impl(
 3506                        RewrapOptions {
 3507                            override_language_settings: true,
 3508                            preserve_existing_whitespace: true,
 3509                        },
 3510                        cx,
 3511                    )
 3512                }
 3513            }
 3514            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3515            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3516            this.refresh_inline_completion(true, false, window, cx);
 3517            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3518        });
 3519    }
 3520
 3521    fn find_possible_emoji_shortcode_at_position(
 3522        snapshot: &MultiBufferSnapshot,
 3523        position: Point,
 3524    ) -> Option<String> {
 3525        let mut chars = Vec::new();
 3526        let mut found_colon = false;
 3527        for char in snapshot.reversed_chars_at(position).take(100) {
 3528            // Found a possible emoji shortcode in the middle of the buffer
 3529            if found_colon {
 3530                if char.is_whitespace() {
 3531                    chars.reverse();
 3532                    return Some(chars.iter().collect());
 3533                }
 3534                // If the previous character is not a whitespace, we are in the middle of a word
 3535                // and we only want to complete the shortcode if the word is made up of other emojis
 3536                let mut containing_word = String::new();
 3537                for ch in snapshot
 3538                    .reversed_chars_at(position)
 3539                    .skip(chars.len() + 1)
 3540                    .take(100)
 3541                {
 3542                    if ch.is_whitespace() {
 3543                        break;
 3544                    }
 3545                    containing_word.push(ch);
 3546                }
 3547                let containing_word = containing_word.chars().rev().collect::<String>();
 3548                if util::word_consists_of_emojis(containing_word.as_str()) {
 3549                    chars.reverse();
 3550                    return Some(chars.iter().collect());
 3551                }
 3552            }
 3553
 3554            if char.is_whitespace() || !char.is_ascii() {
 3555                return None;
 3556            }
 3557            if char == ':' {
 3558                found_colon = true;
 3559            } else {
 3560                chars.push(char);
 3561            }
 3562        }
 3563        // Found a possible emoji shortcode at the beginning of the buffer
 3564        chars.reverse();
 3565        Some(chars.iter().collect())
 3566    }
 3567
 3568    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3569        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3570        self.transact(window, cx, |this, window, cx| {
 3571            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3572                let selections = this.selections.all::<usize>(cx);
 3573                let multi_buffer = this.buffer.read(cx);
 3574                let buffer = multi_buffer.snapshot(cx);
 3575                selections
 3576                    .iter()
 3577                    .map(|selection| {
 3578                        let start_point = selection.start.to_point(&buffer);
 3579                        let mut indent =
 3580                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3581                        indent.len = cmp::min(indent.len, start_point.column);
 3582                        let start = selection.start;
 3583                        let end = selection.end;
 3584                        let selection_is_empty = start == end;
 3585                        let language_scope = buffer.language_scope_at(start);
 3586                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3587                            &language_scope
 3588                        {
 3589                            let insert_extra_newline =
 3590                                insert_extra_newline_brackets(&buffer, start..end, language)
 3591                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3592
 3593                            // Comment extension on newline is allowed only for cursor selections
 3594                            let comment_delimiter = maybe!({
 3595                                if !selection_is_empty {
 3596                                    return None;
 3597                                }
 3598
 3599                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3600                                    return None;
 3601                                }
 3602
 3603                                let delimiters = language.line_comment_prefixes();
 3604                                let max_len_of_delimiter =
 3605                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3606                                let (snapshot, range) =
 3607                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3608
 3609                                let mut index_of_first_non_whitespace = 0;
 3610                                let comment_candidate = snapshot
 3611                                    .chars_for_range(range)
 3612                                    .skip_while(|c| {
 3613                                        let should_skip = c.is_whitespace();
 3614                                        if should_skip {
 3615                                            index_of_first_non_whitespace += 1;
 3616                                        }
 3617                                        should_skip
 3618                                    })
 3619                                    .take(max_len_of_delimiter)
 3620                                    .collect::<String>();
 3621                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3622                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3623                                })?;
 3624                                let cursor_is_placed_after_comment_marker =
 3625                                    index_of_first_non_whitespace + comment_prefix.len()
 3626                                        <= start_point.column as usize;
 3627                                if cursor_is_placed_after_comment_marker {
 3628                                    Some(comment_prefix.clone())
 3629                                } else {
 3630                                    None
 3631                                }
 3632                            });
 3633                            (comment_delimiter, insert_extra_newline)
 3634                        } else {
 3635                            (None, false)
 3636                        };
 3637
 3638                        let capacity_for_delimiter = comment_delimiter
 3639                            .as_deref()
 3640                            .map(str::len)
 3641                            .unwrap_or_default();
 3642                        let mut new_text =
 3643                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3644                        new_text.push('\n');
 3645                        new_text.extend(indent.chars());
 3646                        if let Some(delimiter) = &comment_delimiter {
 3647                            new_text.push_str(delimiter);
 3648                        }
 3649                        if insert_extra_newline {
 3650                            new_text = new_text.repeat(2);
 3651                        }
 3652
 3653                        let anchor = buffer.anchor_after(end);
 3654                        let new_selection = selection.map(|_| anchor);
 3655                        (
 3656                            (start..end, new_text),
 3657                            (insert_extra_newline, new_selection),
 3658                        )
 3659                    })
 3660                    .unzip()
 3661            };
 3662
 3663            this.edit_with_autoindent(edits, cx);
 3664            let buffer = this.buffer.read(cx).snapshot(cx);
 3665            let new_selections = selection_fixup_info
 3666                .into_iter()
 3667                .map(|(extra_newline_inserted, new_selection)| {
 3668                    let mut cursor = new_selection.end.to_point(&buffer);
 3669                    if extra_newline_inserted {
 3670                        cursor.row -= 1;
 3671                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3672                    }
 3673                    new_selection.map(|_| cursor)
 3674                })
 3675                .collect();
 3676
 3677            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3678                s.select(new_selections)
 3679            });
 3680            this.refresh_inline_completion(true, false, window, cx);
 3681        });
 3682    }
 3683
 3684    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 3685        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3686
 3687        let buffer = self.buffer.read(cx);
 3688        let snapshot = buffer.snapshot(cx);
 3689
 3690        let mut edits = Vec::new();
 3691        let mut rows = Vec::new();
 3692
 3693        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3694            let cursor = selection.head();
 3695            let row = cursor.row;
 3696
 3697            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3698
 3699            let newline = "\n".to_string();
 3700            edits.push((start_of_line..start_of_line, newline));
 3701
 3702            rows.push(row + rows_inserted as u32);
 3703        }
 3704
 3705        self.transact(window, cx, |editor, window, cx| {
 3706            editor.edit(edits, cx);
 3707
 3708            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3709                let mut index = 0;
 3710                s.move_cursors_with(|map, _, _| {
 3711                    let row = rows[index];
 3712                    index += 1;
 3713
 3714                    let point = Point::new(row, 0);
 3715                    let boundary = map.next_line_boundary(point).1;
 3716                    let clipped = map.clip_point(boundary, Bias::Left);
 3717
 3718                    (clipped, SelectionGoal::None)
 3719                });
 3720            });
 3721
 3722            let mut indent_edits = Vec::new();
 3723            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3724            for row in rows {
 3725                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3726                for (row, indent) in indents {
 3727                    if indent.len == 0 {
 3728                        continue;
 3729                    }
 3730
 3731                    let text = match indent.kind {
 3732                        IndentKind::Space => " ".repeat(indent.len as usize),
 3733                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3734                    };
 3735                    let point = Point::new(row.0, 0);
 3736                    indent_edits.push((point..point, text));
 3737                }
 3738            }
 3739            editor.edit(indent_edits, cx);
 3740        });
 3741    }
 3742
 3743    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 3744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3745
 3746        let buffer = self.buffer.read(cx);
 3747        let snapshot = buffer.snapshot(cx);
 3748
 3749        let mut edits = Vec::new();
 3750        let mut rows = Vec::new();
 3751        let mut rows_inserted = 0;
 3752
 3753        for selection in self.selections.all_adjusted(cx) {
 3754            let cursor = selection.head();
 3755            let row = cursor.row;
 3756
 3757            let point = Point::new(row + 1, 0);
 3758            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3759
 3760            let newline = "\n".to_string();
 3761            edits.push((start_of_line..start_of_line, newline));
 3762
 3763            rows_inserted += 1;
 3764            rows.push(row + rows_inserted);
 3765        }
 3766
 3767        self.transact(window, cx, |editor, window, cx| {
 3768            editor.edit(edits, cx);
 3769
 3770            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3771                let mut index = 0;
 3772                s.move_cursors_with(|map, _, _| {
 3773                    let row = rows[index];
 3774                    index += 1;
 3775
 3776                    let point = Point::new(row, 0);
 3777                    let boundary = map.next_line_boundary(point).1;
 3778                    let clipped = map.clip_point(boundary, Bias::Left);
 3779
 3780                    (clipped, SelectionGoal::None)
 3781                });
 3782            });
 3783
 3784            let mut indent_edits = Vec::new();
 3785            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3786            for row in rows {
 3787                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3788                for (row, indent) in indents {
 3789                    if indent.len == 0 {
 3790                        continue;
 3791                    }
 3792
 3793                    let text = match indent.kind {
 3794                        IndentKind::Space => " ".repeat(indent.len as usize),
 3795                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3796                    };
 3797                    let point = Point::new(row.0, 0);
 3798                    indent_edits.push((point..point, text));
 3799                }
 3800            }
 3801            editor.edit(indent_edits, cx);
 3802        });
 3803    }
 3804
 3805    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3806        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3807            original_indent_columns: Vec::new(),
 3808        });
 3809        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 3810    }
 3811
 3812    fn insert_with_autoindent_mode(
 3813        &mut self,
 3814        text: &str,
 3815        autoindent_mode: Option<AutoindentMode>,
 3816        window: &mut Window,
 3817        cx: &mut Context<Self>,
 3818    ) {
 3819        if self.read_only(cx) {
 3820            return;
 3821        }
 3822
 3823        let text: Arc<str> = text.into();
 3824        self.transact(window, cx, |this, window, cx| {
 3825            let old_selections = this.selections.all_adjusted(cx);
 3826            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3827                let anchors = {
 3828                    let snapshot = buffer.read(cx);
 3829                    old_selections
 3830                        .iter()
 3831                        .map(|s| {
 3832                            let anchor = snapshot.anchor_after(s.head());
 3833                            s.map(|_| anchor)
 3834                        })
 3835                        .collect::<Vec<_>>()
 3836                };
 3837                buffer.edit(
 3838                    old_selections
 3839                        .iter()
 3840                        .map(|s| (s.start..s.end, text.clone())),
 3841                    autoindent_mode,
 3842                    cx,
 3843                );
 3844                anchors
 3845            });
 3846
 3847            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3848                s.select_anchors(selection_anchors);
 3849            });
 3850
 3851            cx.notify();
 3852        });
 3853    }
 3854
 3855    fn trigger_completion_on_input(
 3856        &mut self,
 3857        text: &str,
 3858        trigger_in_words: bool,
 3859        window: &mut Window,
 3860        cx: &mut Context<Self>,
 3861    ) {
 3862        let ignore_completion_provider = self
 3863            .context_menu
 3864            .borrow()
 3865            .as_ref()
 3866            .map(|menu| match menu {
 3867                CodeContextMenu::Completions(completions_menu) => {
 3868                    completions_menu.ignore_completion_provider
 3869                }
 3870                CodeContextMenu::CodeActions(_) => false,
 3871            })
 3872            .unwrap_or(false);
 3873
 3874        if ignore_completion_provider {
 3875            self.show_word_completions(&ShowWordCompletions, window, cx);
 3876        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 3877            self.show_completions(
 3878                &ShowCompletions {
 3879                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 3880                },
 3881                window,
 3882                cx,
 3883            );
 3884        } else {
 3885            self.hide_context_menu(window, cx);
 3886        }
 3887    }
 3888
 3889    fn is_completion_trigger(
 3890        &self,
 3891        text: &str,
 3892        trigger_in_words: bool,
 3893        cx: &mut Context<Self>,
 3894    ) -> bool {
 3895        let position = self.selections.newest_anchor().head();
 3896        let multibuffer = self.buffer.read(cx);
 3897        let Some(buffer) = position
 3898            .buffer_id
 3899            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 3900        else {
 3901            return false;
 3902        };
 3903
 3904        if let Some(completion_provider) = &self.completion_provider {
 3905            completion_provider.is_completion_trigger(
 3906                &buffer,
 3907                position.text_anchor,
 3908                text,
 3909                trigger_in_words,
 3910                cx,
 3911            )
 3912        } else {
 3913            false
 3914        }
 3915    }
 3916
 3917    /// If any empty selections is touching the start of its innermost containing autoclose
 3918    /// region, expand it to select the brackets.
 3919    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3920        let selections = self.selections.all::<usize>(cx);
 3921        let buffer = self.buffer.read(cx).read(cx);
 3922        let new_selections = self
 3923            .selections_with_autoclose_regions(selections, &buffer)
 3924            .map(|(mut selection, region)| {
 3925                if !selection.is_empty() {
 3926                    return selection;
 3927                }
 3928
 3929                if let Some(region) = region {
 3930                    let mut range = region.range.to_offset(&buffer);
 3931                    if selection.start == range.start && range.start >= region.pair.start.len() {
 3932                        range.start -= region.pair.start.len();
 3933                        if buffer.contains_str_at(range.start, &region.pair.start)
 3934                            && buffer.contains_str_at(range.end, &region.pair.end)
 3935                        {
 3936                            range.end += region.pair.end.len();
 3937                            selection.start = range.start;
 3938                            selection.end = range.end;
 3939
 3940                            return selection;
 3941                        }
 3942                    }
 3943                }
 3944
 3945                let always_treat_brackets_as_autoclosed = buffer
 3946                    .language_settings_at(selection.start, cx)
 3947                    .always_treat_brackets_as_autoclosed;
 3948
 3949                if !always_treat_brackets_as_autoclosed {
 3950                    return selection;
 3951                }
 3952
 3953                if let Some(scope) = buffer.language_scope_at(selection.start) {
 3954                    for (pair, enabled) in scope.brackets() {
 3955                        if !enabled || !pair.close {
 3956                            continue;
 3957                        }
 3958
 3959                        if buffer.contains_str_at(selection.start, &pair.end) {
 3960                            let pair_start_len = pair.start.len();
 3961                            if buffer.contains_str_at(
 3962                                selection.start.saturating_sub(pair_start_len),
 3963                                &pair.start,
 3964                            ) {
 3965                                selection.start -= pair_start_len;
 3966                                selection.end += pair.end.len();
 3967
 3968                                return selection;
 3969                            }
 3970                        }
 3971                    }
 3972                }
 3973
 3974                selection
 3975            })
 3976            .collect();
 3977
 3978        drop(buffer);
 3979        self.change_selections(None, window, cx, |selections| {
 3980            selections.select(new_selections)
 3981        });
 3982    }
 3983
 3984    /// Iterate the given selections, and for each one, find the smallest surrounding
 3985    /// autoclose region. This uses the ordering of the selections and the autoclose
 3986    /// regions to avoid repeated comparisons.
 3987    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 3988        &'a self,
 3989        selections: impl IntoIterator<Item = Selection<D>>,
 3990        buffer: &'a MultiBufferSnapshot,
 3991    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 3992        let mut i = 0;
 3993        let mut regions = self.autoclose_regions.as_slice();
 3994        selections.into_iter().map(move |selection| {
 3995            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 3996
 3997            let mut enclosing = None;
 3998            while let Some(pair_state) = regions.get(i) {
 3999                if pair_state.range.end.to_offset(buffer) < range.start {
 4000                    regions = &regions[i + 1..];
 4001                    i = 0;
 4002                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4003                    break;
 4004                } else {
 4005                    if pair_state.selection_id == selection.id {
 4006                        enclosing = Some(pair_state);
 4007                    }
 4008                    i += 1;
 4009                }
 4010            }
 4011
 4012            (selection, enclosing)
 4013        })
 4014    }
 4015
 4016    /// Remove any autoclose regions that no longer contain their selection.
 4017    fn invalidate_autoclose_regions(
 4018        &mut self,
 4019        mut selections: &[Selection<Anchor>],
 4020        buffer: &MultiBufferSnapshot,
 4021    ) {
 4022        self.autoclose_regions.retain(|state| {
 4023            let mut i = 0;
 4024            while let Some(selection) = selections.get(i) {
 4025                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4026                    selections = &selections[1..];
 4027                    continue;
 4028                }
 4029                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4030                    break;
 4031                }
 4032                if selection.id == state.selection_id {
 4033                    return true;
 4034                } else {
 4035                    i += 1;
 4036                }
 4037            }
 4038            false
 4039        });
 4040    }
 4041
 4042    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4043        let offset = position.to_offset(buffer);
 4044        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4045        if offset > word_range.start && kind == Some(CharKind::Word) {
 4046            Some(
 4047                buffer
 4048                    .text_for_range(word_range.start..offset)
 4049                    .collect::<String>(),
 4050            )
 4051        } else {
 4052            None
 4053        }
 4054    }
 4055
 4056    pub fn toggle_inlay_hints(
 4057        &mut self,
 4058        _: &ToggleInlayHints,
 4059        _: &mut Window,
 4060        cx: &mut Context<Self>,
 4061    ) {
 4062        self.refresh_inlay_hints(
 4063            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4064            cx,
 4065        );
 4066    }
 4067
 4068    pub fn inlay_hints_enabled(&self) -> bool {
 4069        self.inlay_hint_cache.enabled
 4070    }
 4071
 4072    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4073        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4074            return;
 4075        }
 4076
 4077        let reason_description = reason.description();
 4078        let ignore_debounce = matches!(
 4079            reason,
 4080            InlayHintRefreshReason::SettingsChange(_)
 4081                | InlayHintRefreshReason::Toggle(_)
 4082                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4083                | InlayHintRefreshReason::ModifiersChanged(_)
 4084        );
 4085        let (invalidate_cache, required_languages) = match reason {
 4086            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4087                match self.inlay_hint_cache.modifiers_override(enabled) {
 4088                    Some(enabled) => {
 4089                        if enabled {
 4090                            (InvalidationStrategy::RefreshRequested, None)
 4091                        } else {
 4092                            self.splice_inlays(
 4093                                &self
 4094                                    .visible_inlay_hints(cx)
 4095                                    .iter()
 4096                                    .map(|inlay| inlay.id)
 4097                                    .collect::<Vec<InlayId>>(),
 4098                                Vec::new(),
 4099                                cx,
 4100                            );
 4101                            return;
 4102                        }
 4103                    }
 4104                    None => return,
 4105                }
 4106            }
 4107            InlayHintRefreshReason::Toggle(enabled) => {
 4108                if self.inlay_hint_cache.toggle(enabled) {
 4109                    if enabled {
 4110                        (InvalidationStrategy::RefreshRequested, None)
 4111                    } else {
 4112                        self.splice_inlays(
 4113                            &self
 4114                                .visible_inlay_hints(cx)
 4115                                .iter()
 4116                                .map(|inlay| inlay.id)
 4117                                .collect::<Vec<InlayId>>(),
 4118                            Vec::new(),
 4119                            cx,
 4120                        );
 4121                        return;
 4122                    }
 4123                } else {
 4124                    return;
 4125                }
 4126            }
 4127            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4128                match self.inlay_hint_cache.update_settings(
 4129                    &self.buffer,
 4130                    new_settings,
 4131                    self.visible_inlay_hints(cx),
 4132                    cx,
 4133                ) {
 4134                    ControlFlow::Break(Some(InlaySplice {
 4135                        to_remove,
 4136                        to_insert,
 4137                    })) => {
 4138                        self.splice_inlays(&to_remove, to_insert, cx);
 4139                        return;
 4140                    }
 4141                    ControlFlow::Break(None) => return,
 4142                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4143                }
 4144            }
 4145            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4146                if let Some(InlaySplice {
 4147                    to_remove,
 4148                    to_insert,
 4149                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 4150                {
 4151                    self.splice_inlays(&to_remove, to_insert, cx);
 4152                }
 4153                return;
 4154            }
 4155            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4156            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4157                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4158            }
 4159            InlayHintRefreshReason::RefreshRequested => {
 4160                (InvalidationStrategy::RefreshRequested, None)
 4161            }
 4162        };
 4163
 4164        if let Some(InlaySplice {
 4165            to_remove,
 4166            to_insert,
 4167        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4168            reason_description,
 4169            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4170            invalidate_cache,
 4171            ignore_debounce,
 4172            cx,
 4173        ) {
 4174            self.splice_inlays(&to_remove, to_insert, cx);
 4175        }
 4176    }
 4177
 4178    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4179        self.display_map
 4180            .read(cx)
 4181            .current_inlays()
 4182            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4183            .cloned()
 4184            .collect()
 4185    }
 4186
 4187    pub fn excerpts_for_inlay_hints_query(
 4188        &self,
 4189        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4190        cx: &mut Context<Editor>,
 4191    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4192        let Some(project) = self.project.as_ref() else {
 4193            return HashMap::default();
 4194        };
 4195        let project = project.read(cx);
 4196        let multi_buffer = self.buffer().read(cx);
 4197        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4198        let multi_buffer_visible_start = self
 4199            .scroll_manager
 4200            .anchor()
 4201            .anchor
 4202            .to_point(&multi_buffer_snapshot);
 4203        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4204            multi_buffer_visible_start
 4205                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4206            Bias::Left,
 4207        );
 4208        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4209        multi_buffer_snapshot
 4210            .range_to_buffer_ranges(multi_buffer_visible_range)
 4211            .into_iter()
 4212            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4213            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4214                let buffer_file = project::File::from_dyn(buffer.file())?;
 4215                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4216                let worktree_entry = buffer_worktree
 4217                    .read(cx)
 4218                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4219                if worktree_entry.is_ignored {
 4220                    return None;
 4221                }
 4222
 4223                let language = buffer.language()?;
 4224                if let Some(restrict_to_languages) = restrict_to_languages {
 4225                    if !restrict_to_languages.contains(language) {
 4226                        return None;
 4227                    }
 4228                }
 4229                Some((
 4230                    excerpt_id,
 4231                    (
 4232                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4233                        buffer.version().clone(),
 4234                        excerpt_visible_range,
 4235                    ),
 4236                ))
 4237            })
 4238            .collect()
 4239    }
 4240
 4241    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4242        TextLayoutDetails {
 4243            text_system: window.text_system().clone(),
 4244            editor_style: self.style.clone().unwrap(),
 4245            rem_size: window.rem_size(),
 4246            scroll_anchor: self.scroll_manager.anchor(),
 4247            visible_rows: self.visible_line_count(),
 4248            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4249        }
 4250    }
 4251
 4252    pub fn splice_inlays(
 4253        &self,
 4254        to_remove: &[InlayId],
 4255        to_insert: Vec<Inlay>,
 4256        cx: &mut Context<Self>,
 4257    ) {
 4258        self.display_map.update(cx, |display_map, cx| {
 4259            display_map.splice_inlays(to_remove, to_insert, cx)
 4260        });
 4261        cx.notify();
 4262    }
 4263
 4264    fn trigger_on_type_formatting(
 4265        &self,
 4266        input: String,
 4267        window: &mut Window,
 4268        cx: &mut Context<Self>,
 4269    ) -> Option<Task<Result<()>>> {
 4270        if input.len() != 1 {
 4271            return None;
 4272        }
 4273
 4274        let project = self.project.as_ref()?;
 4275        let position = self.selections.newest_anchor().head();
 4276        let (buffer, buffer_position) = self
 4277            .buffer
 4278            .read(cx)
 4279            .text_anchor_for_position(position, cx)?;
 4280
 4281        let settings = language_settings::language_settings(
 4282            buffer
 4283                .read(cx)
 4284                .language_at(buffer_position)
 4285                .map(|l| l.name()),
 4286            buffer.read(cx).file(),
 4287            cx,
 4288        );
 4289        if !settings.use_on_type_format {
 4290            return None;
 4291        }
 4292
 4293        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4294        // hence we do LSP request & edit on host side only — add formats to host's history.
 4295        let push_to_lsp_host_history = true;
 4296        // If this is not the host, append its history with new edits.
 4297        let push_to_client_history = project.read(cx).is_via_collab();
 4298
 4299        let on_type_formatting = project.update(cx, |project, cx| {
 4300            project.on_type_format(
 4301                buffer.clone(),
 4302                buffer_position,
 4303                input,
 4304                push_to_lsp_host_history,
 4305                cx,
 4306            )
 4307        });
 4308        Some(cx.spawn_in(window, async move |editor, cx| {
 4309            if let Some(transaction) = on_type_formatting.await? {
 4310                if push_to_client_history {
 4311                    buffer
 4312                        .update(cx, |buffer, _| {
 4313                            buffer.push_transaction(transaction, Instant::now());
 4314                            buffer.finalize_last_transaction();
 4315                        })
 4316                        .ok();
 4317                }
 4318                editor.update(cx, |editor, cx| {
 4319                    editor.refresh_document_highlights(cx);
 4320                })?;
 4321            }
 4322            Ok(())
 4323        }))
 4324    }
 4325
 4326    pub fn show_word_completions(
 4327        &mut self,
 4328        _: &ShowWordCompletions,
 4329        window: &mut Window,
 4330        cx: &mut Context<Self>,
 4331    ) {
 4332        self.open_completions_menu(true, None, window, cx);
 4333    }
 4334
 4335    pub fn show_completions(
 4336        &mut self,
 4337        options: &ShowCompletions,
 4338        window: &mut Window,
 4339        cx: &mut Context<Self>,
 4340    ) {
 4341        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4342    }
 4343
 4344    fn open_completions_menu(
 4345        &mut self,
 4346        ignore_completion_provider: bool,
 4347        trigger: Option<&str>,
 4348        window: &mut Window,
 4349        cx: &mut Context<Self>,
 4350    ) {
 4351        if self.pending_rename.is_some() {
 4352            return;
 4353        }
 4354        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4355            return;
 4356        }
 4357
 4358        let position = self.selections.newest_anchor().head();
 4359        if position.diff_base_anchor.is_some() {
 4360            return;
 4361        }
 4362        let (buffer, buffer_position) =
 4363            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4364                output
 4365            } else {
 4366                return;
 4367            };
 4368        let buffer_snapshot = buffer.read(cx).snapshot();
 4369        let show_completion_documentation = buffer_snapshot
 4370            .settings_at(buffer_position, cx)
 4371            .show_completion_documentation;
 4372
 4373        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4374
 4375        let trigger_kind = match trigger {
 4376            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4377                CompletionTriggerKind::TRIGGER_CHARACTER
 4378            }
 4379            _ => CompletionTriggerKind::INVOKED,
 4380        };
 4381        let completion_context = CompletionContext {
 4382            trigger_character: trigger.and_then(|trigger| {
 4383                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4384                    Some(String::from(trigger))
 4385                } else {
 4386                    None
 4387                }
 4388            }),
 4389            trigger_kind,
 4390        };
 4391
 4392        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4393        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4394            let word_to_exclude = buffer_snapshot
 4395                .text_for_range(old_range.clone())
 4396                .collect::<String>();
 4397            (
 4398                buffer_snapshot.anchor_before(old_range.start)
 4399                    ..buffer_snapshot.anchor_after(old_range.end),
 4400                Some(word_to_exclude),
 4401            )
 4402        } else {
 4403            (buffer_position..buffer_position, None)
 4404        };
 4405
 4406        let completion_settings = language_settings(
 4407            buffer_snapshot
 4408                .language_at(buffer_position)
 4409                .map(|language| language.name()),
 4410            buffer_snapshot.file(),
 4411            cx,
 4412        )
 4413        .completions;
 4414
 4415        // The document can be large, so stay in reasonable bounds when searching for words,
 4416        // otherwise completion pop-up might be slow to appear.
 4417        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4418        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4419        let min_word_search = buffer_snapshot.clip_point(
 4420            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4421            Bias::Left,
 4422        );
 4423        let max_word_search = buffer_snapshot.clip_point(
 4424            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4425            Bias::Right,
 4426        );
 4427        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4428            ..buffer_snapshot.point_to_offset(max_word_search);
 4429
 4430        let provider = self
 4431            .completion_provider
 4432            .as_ref()
 4433            .filter(|_| !ignore_completion_provider);
 4434        let skip_digits = query
 4435            .as_ref()
 4436            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4437
 4438        let (mut words, provided_completions) = match provider {
 4439            Some(provider) => {
 4440                let completions = provider.completions(
 4441                    position.excerpt_id,
 4442                    &buffer,
 4443                    buffer_position,
 4444                    completion_context,
 4445                    window,
 4446                    cx,
 4447                );
 4448
 4449                let words = match completion_settings.words {
 4450                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4451                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4452                        .background_spawn(async move {
 4453                            buffer_snapshot.words_in_range(WordsQuery {
 4454                                fuzzy_contents: None,
 4455                                range: word_search_range,
 4456                                skip_digits,
 4457                            })
 4458                        }),
 4459                };
 4460
 4461                (words, completions)
 4462            }
 4463            None => (
 4464                cx.background_spawn(async move {
 4465                    buffer_snapshot.words_in_range(WordsQuery {
 4466                        fuzzy_contents: None,
 4467                        range: word_search_range,
 4468                        skip_digits,
 4469                    })
 4470                }),
 4471                Task::ready(Ok(None)),
 4472            ),
 4473        };
 4474
 4475        let sort_completions = provider
 4476            .as_ref()
 4477            .map_or(false, |provider| provider.sort_completions());
 4478
 4479        let filter_completions = provider
 4480            .as_ref()
 4481            .map_or(true, |provider| provider.filter_completions());
 4482
 4483        let id = post_inc(&mut self.next_completion_id);
 4484        let task = cx.spawn_in(window, async move |editor, cx| {
 4485            async move {
 4486                editor.update(cx, |this, _| {
 4487                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4488                })?;
 4489
 4490                let mut completions = Vec::new();
 4491                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 4492                    completions.extend(provided_completions);
 4493                    if completion_settings.words == WordsCompletionMode::Fallback {
 4494                        words = Task::ready(BTreeMap::default());
 4495                    }
 4496                }
 4497
 4498                let mut words = words.await;
 4499                if let Some(word_to_exclude) = &word_to_exclude {
 4500                    words.remove(word_to_exclude);
 4501                }
 4502                for lsp_completion in &completions {
 4503                    words.remove(&lsp_completion.new_text);
 4504                }
 4505                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 4506                    replace_range: old_range.clone(),
 4507                    new_text: word.clone(),
 4508                    label: CodeLabel::plain(word, None),
 4509                    icon_path: None,
 4510                    documentation: None,
 4511                    source: CompletionSource::BufferWord {
 4512                        word_range,
 4513                        resolved: false,
 4514                    },
 4515                    insert_text_mode: Some(InsertTextMode::AS_IS),
 4516                    confirm: None,
 4517                }));
 4518
 4519                let menu = if completions.is_empty() {
 4520                    None
 4521                } else {
 4522                    let mut menu = CompletionsMenu::new(
 4523                        id,
 4524                        sort_completions,
 4525                        show_completion_documentation,
 4526                        ignore_completion_provider,
 4527                        position,
 4528                        buffer.clone(),
 4529                        completions.into(),
 4530                    );
 4531
 4532                    menu.filter(
 4533                        if filter_completions {
 4534                            query.as_deref()
 4535                        } else {
 4536                            None
 4537                        },
 4538                        cx.background_executor().clone(),
 4539                    )
 4540                    .await;
 4541
 4542                    menu.visible().then_some(menu)
 4543                };
 4544
 4545                editor.update_in(cx, |editor, window, cx| {
 4546                    match editor.context_menu.borrow().as_ref() {
 4547                        None => {}
 4548                        Some(CodeContextMenu::Completions(prev_menu)) => {
 4549                            if prev_menu.id > id {
 4550                                return;
 4551                            }
 4552                        }
 4553                        _ => return,
 4554                    }
 4555
 4556                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4557                        let mut menu = menu.unwrap();
 4558                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4559
 4560                        *editor.context_menu.borrow_mut() =
 4561                            Some(CodeContextMenu::Completions(menu));
 4562
 4563                        if editor.show_edit_predictions_in_menu() {
 4564                            editor.update_visible_inline_completion(window, cx);
 4565                        } else {
 4566                            editor.discard_inline_completion(false, cx);
 4567                        }
 4568
 4569                        cx.notify();
 4570                    } else if editor.completion_tasks.len() <= 1 {
 4571                        // If there are no more completion tasks and the last menu was
 4572                        // empty, we should hide it.
 4573                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4574                        // If it was already hidden and we don't show inline
 4575                        // completions in the menu, we should also show the
 4576                        // inline-completion when available.
 4577                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4578                            editor.update_visible_inline_completion(window, cx);
 4579                        }
 4580                    }
 4581                })?;
 4582
 4583                anyhow::Ok(())
 4584            }
 4585            .log_err()
 4586            .await
 4587        });
 4588
 4589        self.completion_tasks.push((id, task));
 4590    }
 4591
 4592    #[cfg(feature = "test-support")]
 4593    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 4594        let menu = self.context_menu.borrow();
 4595        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 4596            let completions = menu.completions.borrow();
 4597            Some(completions.to_vec())
 4598        } else {
 4599            None
 4600        }
 4601    }
 4602
 4603    pub fn confirm_completion(
 4604        &mut self,
 4605        action: &ConfirmCompletion,
 4606        window: &mut Window,
 4607        cx: &mut Context<Self>,
 4608    ) -> Option<Task<Result<()>>> {
 4609        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4610        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4611    }
 4612
 4613    pub fn confirm_completion_insert(
 4614        &mut self,
 4615        _: &ConfirmCompletionInsert,
 4616        window: &mut Window,
 4617        cx: &mut Context<Self>,
 4618    ) -> Option<Task<Result<()>>> {
 4619        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4620        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 4621    }
 4622
 4623    pub fn confirm_completion_replace(
 4624        &mut self,
 4625        _: &ConfirmCompletionReplace,
 4626        window: &mut Window,
 4627        cx: &mut Context<Self>,
 4628    ) -> Option<Task<Result<()>>> {
 4629        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4630        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 4631    }
 4632
 4633    pub fn compose_completion(
 4634        &mut self,
 4635        action: &ComposeCompletion,
 4636        window: &mut Window,
 4637        cx: &mut Context<Self>,
 4638    ) -> Option<Task<Result<()>>> {
 4639        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4640        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 4641    }
 4642
 4643    fn do_completion(
 4644        &mut self,
 4645        item_ix: Option<usize>,
 4646        intent: CompletionIntent,
 4647        window: &mut Window,
 4648        cx: &mut Context<Editor>,
 4649    ) -> Option<Task<Result<()>>> {
 4650        use language::ToOffset as _;
 4651
 4652        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 4653        else {
 4654            return None;
 4655        };
 4656
 4657        let candidate_id = {
 4658            let entries = completions_menu.entries.borrow();
 4659            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4660            if self.show_edit_predictions_in_menu() {
 4661                self.discard_inline_completion(true, cx);
 4662            }
 4663            mat.candidate_id
 4664        };
 4665
 4666        let buffer_handle = completions_menu.buffer;
 4667        let completion = completions_menu
 4668            .completions
 4669            .borrow()
 4670            .get(candidate_id)?
 4671            .clone();
 4672        cx.stop_propagation();
 4673
 4674        let snippet;
 4675        let new_text;
 4676        if completion.is_snippet() {
 4677            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4678            new_text = snippet.as_ref().unwrap().text.clone();
 4679        } else {
 4680            snippet = None;
 4681            new_text = completion.new_text.clone();
 4682        };
 4683
 4684        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 4685        let buffer = buffer_handle.read(cx);
 4686        let snapshot = self.buffer.read(cx).snapshot(cx);
 4687        let replace_range_multibuffer = {
 4688            let excerpt = snapshot
 4689                .excerpt_containing(self.selections.newest_anchor().range())
 4690                .unwrap();
 4691            let multibuffer_anchor = snapshot
 4692                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 4693                .unwrap()
 4694                ..snapshot
 4695                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 4696                    .unwrap();
 4697            multibuffer_anchor.start.to_offset(&snapshot)
 4698                ..multibuffer_anchor.end.to_offset(&snapshot)
 4699        };
 4700        let newest_anchor = self.selections.newest_anchor();
 4701        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 4702            return None;
 4703        }
 4704
 4705        let old_text = buffer
 4706            .text_for_range(replace_range.clone())
 4707            .collect::<String>();
 4708        let lookbehind = newest_anchor
 4709            .start
 4710            .text_anchor
 4711            .to_offset(buffer)
 4712            .saturating_sub(replace_range.start);
 4713        let lookahead = replace_range
 4714            .end
 4715            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 4716        let prefix = &old_text[..old_text.len() - lookahead];
 4717        let suffix = &old_text[lookbehind..];
 4718
 4719        let selections = self.selections.all::<usize>(cx);
 4720        let mut edits = Vec::new();
 4721        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4722
 4723        for selection in &selections {
 4724            let edit = if selection.id == newest_anchor.id {
 4725                (replace_range_multibuffer.clone(), new_text.as_str())
 4726            } else {
 4727                let mut range = selection.range();
 4728                let mut text = new_text.as_str();
 4729
 4730                // if prefix is present, don't duplicate it
 4731                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 4732                    text = &new_text[lookbehind..];
 4733
 4734                    // if suffix is also present, mimic the newest cursor and replace it
 4735                    if selection.id != newest_anchor.id
 4736                        && snapshot.contains_str_at(range.end, suffix)
 4737                    {
 4738                        range.end += lookahead;
 4739                    }
 4740                }
 4741                (range, text)
 4742            };
 4743
 4744            edits.push(edit);
 4745
 4746            if !self.linked_edit_ranges.is_empty() {
 4747                let start_anchor = snapshot.anchor_before(selection.head());
 4748                let end_anchor = snapshot.anchor_after(selection.tail());
 4749                if let Some(ranges) = self
 4750                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4751                {
 4752                    for (buffer, edits) in ranges {
 4753                        linked_edits
 4754                            .entry(buffer.clone())
 4755                            .or_default()
 4756                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 4757                    }
 4758                }
 4759            }
 4760        }
 4761
 4762        cx.emit(EditorEvent::InputHandled {
 4763            utf16_range_to_replace: None,
 4764            text: new_text.clone().into(),
 4765        });
 4766
 4767        self.transact(window, cx, |this, window, cx| {
 4768            if let Some(mut snippet) = snippet {
 4769                snippet.text = new_text.to_string();
 4770                let ranges = edits
 4771                    .iter()
 4772                    .map(|(range, _)| range.clone())
 4773                    .collect::<Vec<_>>();
 4774                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 4775            } else {
 4776                this.buffer.update(cx, |buffer, cx| {
 4777                    let auto_indent = if completion.insert_text_mode == Some(InsertTextMode::AS_IS)
 4778                    {
 4779                        None
 4780                    } else {
 4781                        this.autoindent_mode.clone()
 4782                    };
 4783                    buffer.edit(edits, auto_indent, cx);
 4784                });
 4785            }
 4786            for (buffer, edits) in linked_edits {
 4787                buffer.update(cx, |buffer, cx| {
 4788                    let snapshot = buffer.snapshot();
 4789                    let edits = edits
 4790                        .into_iter()
 4791                        .map(|(range, text)| {
 4792                            use text::ToPoint as TP;
 4793                            let end_point = TP::to_point(&range.end, &snapshot);
 4794                            let start_point = TP::to_point(&range.start, &snapshot);
 4795                            (start_point..end_point, text)
 4796                        })
 4797                        .sorted_by_key(|(range, _)| range.start);
 4798                    buffer.edit(edits, None, cx);
 4799                })
 4800            }
 4801
 4802            this.refresh_inline_completion(true, false, window, cx);
 4803        });
 4804
 4805        let show_new_completions_on_confirm = completion
 4806            .confirm
 4807            .as_ref()
 4808            .map_or(false, |confirm| confirm(intent, window, cx));
 4809        if show_new_completions_on_confirm {
 4810            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 4811        }
 4812
 4813        let provider = self.completion_provider.as_ref()?;
 4814        drop(completion);
 4815        let apply_edits = provider.apply_additional_edits_for_completion(
 4816            buffer_handle,
 4817            completions_menu.completions.clone(),
 4818            candidate_id,
 4819            true,
 4820            cx,
 4821        );
 4822
 4823        let editor_settings = EditorSettings::get_global(cx);
 4824        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 4825            // After the code completion is finished, users often want to know what signatures are needed.
 4826            // so we should automatically call signature_help
 4827            self.show_signature_help(&ShowSignatureHelp, window, cx);
 4828        }
 4829
 4830        Some(cx.foreground_executor().spawn(async move {
 4831            apply_edits.await?;
 4832            Ok(())
 4833        }))
 4834    }
 4835
 4836    fn prepare_code_actions_task(
 4837        &mut self,
 4838        action: &ToggleCodeActions,
 4839        window: &mut Window,
 4840        cx: &mut Context<Self>,
 4841    ) -> Task<Option<(Entity<Buffer>, CodeActionContents)>> {
 4842        let snapshot = self.snapshot(window, cx);
 4843        let multibuffer_point = action
 4844            .deployed_from_indicator
 4845            .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4846            .unwrap_or_else(|| self.selections.newest::<Point>(cx).head());
 4847
 4848        let Some((buffer, buffer_row)) = snapshot
 4849            .buffer_snapshot
 4850            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4851            .and_then(|(buffer_snapshot, range)| {
 4852                self.buffer
 4853                    .read(cx)
 4854                    .buffer(buffer_snapshot.remote_id())
 4855                    .map(|buffer| (buffer, range.start.row))
 4856            })
 4857        else {
 4858            return Task::ready(None);
 4859        };
 4860
 4861        let (_, code_actions) = self
 4862            .available_code_actions
 4863            .clone()
 4864            .and_then(|(location, code_actions)| {
 4865                let snapshot = location.buffer.read(cx).snapshot();
 4866                let point_range = location.range.to_point(&snapshot);
 4867                let point_range = point_range.start.row..=point_range.end.row;
 4868                if point_range.contains(&buffer_row) {
 4869                    Some((location, code_actions))
 4870                } else {
 4871                    None
 4872                }
 4873            })
 4874            .unzip();
 4875
 4876        let buffer_id = buffer.read(cx).remote_id();
 4877        let tasks = self
 4878            .tasks
 4879            .get(&(buffer_id, buffer_row))
 4880            .map(|t| Arc::new(t.to_owned()));
 4881
 4882        if tasks.is_none() && code_actions.is_none() {
 4883            return Task::ready(None);
 4884        }
 4885
 4886        self.completion_tasks.clear();
 4887        self.discard_inline_completion(false, cx);
 4888
 4889        let task_context = tasks
 4890            .as_ref()
 4891            .zip(self.project.clone())
 4892            .map(|(tasks, project)| {
 4893                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 4894            });
 4895
 4896        cx.spawn_in(window, async move |_, _| {
 4897            let task_context = match task_context {
 4898                Some(task_context) => task_context.await,
 4899                None => None,
 4900            };
 4901            let resolved_tasks = tasks.zip(task_context).map(|(tasks, task_context)| {
 4902                Rc::new(ResolvedTasks {
 4903                    templates: tasks.resolve(&task_context).collect(),
 4904                    position: snapshot
 4905                        .buffer_snapshot
 4906                        .anchor_before(Point::new(multibuffer_point.row, tasks.column)),
 4907                })
 4908            });
 4909            Some((
 4910                buffer,
 4911                CodeActionContents {
 4912                    actions: code_actions,
 4913                    tasks: resolved_tasks,
 4914                },
 4915            ))
 4916        })
 4917    }
 4918
 4919    pub fn toggle_code_actions(
 4920        &mut self,
 4921        action: &ToggleCodeActions,
 4922        window: &mut Window,
 4923        cx: &mut Context<Self>,
 4924    ) {
 4925        let mut context_menu = self.context_menu.borrow_mut();
 4926        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 4927            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 4928                // Toggle if we're selecting the same one
 4929                *context_menu = None;
 4930                cx.notify();
 4931                return;
 4932            } else {
 4933                // Otherwise, clear it and start a new one
 4934                *context_menu = None;
 4935                cx.notify();
 4936            }
 4937        }
 4938        drop(context_menu);
 4939
 4940        let deployed_from_indicator = action.deployed_from_indicator;
 4941        let mut task = self.code_actions_task.take();
 4942        let action = action.clone();
 4943
 4944        cx.spawn_in(window, async move |editor, cx| {
 4945            while let Some(prev_task) = task {
 4946                prev_task.await.log_err();
 4947                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 4948            }
 4949
 4950            let context_menu_task = editor.update_in(cx, |editor, window, cx| {
 4951                if !editor.focus_handle.is_focused(window) {
 4952                    return Some(Task::ready(Ok(())));
 4953                }
 4954                let debugger_flag = cx.has_flag::<Debugger>();
 4955                let code_actions_task = editor.prepare_code_actions_task(&action, window, cx);
 4956                Some(cx.spawn_in(window, async move |editor, cx| {
 4957                    if let Some((buffer, code_action_contents)) = code_actions_task.await {
 4958                        let spawn_straight_away =
 4959                            code_action_contents.tasks.as_ref().map_or(false, |tasks| {
 4960                                tasks
 4961                                    .templates
 4962                                    .iter()
 4963                                    .filter(|task| {
 4964                                        if matches!(task.1.task_type(), task::TaskType::Debug(_)) {
 4965                                            debugger_flag
 4966                                        } else {
 4967                                            true
 4968                                        }
 4969                                    })
 4970                                    .count()
 4971                                    == 1
 4972                            }) && code_action_contents
 4973                                .actions
 4974                                .as_ref()
 4975                                .map_or(true, |actions| actions.is_empty());
 4976                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 4977                            *editor.context_menu.borrow_mut() =
 4978                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 4979                                    buffer,
 4980                                    actions: code_action_contents,
 4981                                    selected_item: Default::default(),
 4982                                    scroll_handle: UniformListScrollHandle::default(),
 4983                                    deployed_from_indicator,
 4984                                }));
 4985                            if spawn_straight_away {
 4986                                if let Some(task) = editor.confirm_code_action(
 4987                                    &ConfirmCodeAction {
 4988                                        item_ix: Some(0),
 4989                                        from_mouse_context_menu: false,
 4990                                    },
 4991                                    window,
 4992                                    cx,
 4993                                ) {
 4994                                    cx.notify();
 4995                                    return task;
 4996                                }
 4997                            }
 4998                            cx.notify();
 4999                            Task::ready(Ok(()))
 5000                        }) {
 5001                            task.await
 5002                        } else {
 5003                            Ok(())
 5004                        }
 5005                    } else {
 5006                        Ok(())
 5007                    }
 5008                }))
 5009            })?;
 5010            if let Some(task) = context_menu_task {
 5011                task.await?;
 5012            }
 5013
 5014            Ok::<_, anyhow::Error>(())
 5015        })
 5016        .detach_and_log_err(cx);
 5017    }
 5018
 5019    pub fn confirm_code_action(
 5020        &mut self,
 5021        action: &ConfirmCodeAction,
 5022        window: &mut Window,
 5023        cx: &mut Context<Self>,
 5024    ) -> Option<Task<Result<()>>> {
 5025        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5026
 5027        let (action, buffer) = if action.from_mouse_context_menu {
 5028            if let Some(menu) = self.mouse_context_menu.take() {
 5029                let code_action = menu.code_action?;
 5030                let index = action.item_ix?;
 5031                let action = code_action.actions.get(index)?;
 5032                (action, code_action.buffer)
 5033            } else {
 5034                return None;
 5035            }
 5036        } else {
 5037            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5038                let action_ix = action.item_ix.unwrap_or(menu.selected_item);
 5039                let action = menu.actions.get(action_ix)?;
 5040                let buffer = menu.buffer;
 5041                (action, buffer)
 5042            } else {
 5043                return None;
 5044            }
 5045        };
 5046
 5047        let title = action.label();
 5048        let workspace = self.workspace()?;
 5049
 5050        match action {
 5051            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5052                match resolved_task.task_type() {
 5053                    task::TaskType::Script => workspace.update(cx, |workspace, cx| {
 5054                        workspace::tasks::schedule_resolved_task(
 5055                            workspace,
 5056                            task_source_kind,
 5057                            resolved_task,
 5058                            false,
 5059                            cx,
 5060                        );
 5061
 5062                        Some(Task::ready(Ok(())))
 5063                    }),
 5064                    task::TaskType::Debug(debug_args) => {
 5065                        if debug_args.locator.is_some() {
 5066                            workspace.update(cx, |workspace, cx| {
 5067                                workspace::tasks::schedule_resolved_task(
 5068                                    workspace,
 5069                                    task_source_kind,
 5070                                    resolved_task,
 5071                                    false,
 5072                                    cx,
 5073                                );
 5074                            });
 5075
 5076                            return Some(Task::ready(Ok(())));
 5077                        }
 5078
 5079                        if let Some(project) = self.project.as_ref() {
 5080                            project
 5081                                .update(cx, |project, cx| {
 5082                                    project.start_debug_session(
 5083                                        resolved_task.resolved_debug_adapter_config().unwrap(),
 5084                                        cx,
 5085                                    )
 5086                                })
 5087                                .detach_and_log_err(cx);
 5088                            Some(Task::ready(Ok(())))
 5089                        } else {
 5090                            Some(Task::ready(Ok(())))
 5091                        }
 5092                    }
 5093                }
 5094            }
 5095            CodeActionsItem::CodeAction {
 5096                excerpt_id,
 5097                action,
 5098                provider,
 5099            } => {
 5100                let apply_code_action =
 5101                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5102                let workspace = workspace.downgrade();
 5103                Some(cx.spawn_in(window, async move |editor, cx| {
 5104                    let project_transaction = apply_code_action.await?;
 5105                    Self::open_project_transaction(
 5106                        &editor,
 5107                        workspace,
 5108                        project_transaction,
 5109                        title,
 5110                        cx,
 5111                    )
 5112                    .await
 5113                }))
 5114            }
 5115        }
 5116    }
 5117
 5118    pub async fn open_project_transaction(
 5119        this: &WeakEntity<Editor>,
 5120        workspace: WeakEntity<Workspace>,
 5121        transaction: ProjectTransaction,
 5122        title: String,
 5123        cx: &mut AsyncWindowContext,
 5124    ) -> Result<()> {
 5125        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5126        cx.update(|_, cx| {
 5127            entries.sort_unstable_by_key(|(buffer, _)| {
 5128                buffer.read(cx).file().map(|f| f.path().clone())
 5129            });
 5130        })?;
 5131
 5132        // If the project transaction's edits are all contained within this editor, then
 5133        // avoid opening a new editor to display them.
 5134
 5135        if let Some((buffer, transaction)) = entries.first() {
 5136            if entries.len() == 1 {
 5137                let excerpt = this.update(cx, |editor, cx| {
 5138                    editor
 5139                        .buffer()
 5140                        .read(cx)
 5141                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5142                })?;
 5143                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5144                    if excerpted_buffer == *buffer {
 5145                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5146                            let excerpt_range = excerpt_range.to_offset(buffer);
 5147                            buffer
 5148                                .edited_ranges_for_transaction::<usize>(transaction)
 5149                                .all(|range| {
 5150                                    excerpt_range.start <= range.start
 5151                                        && excerpt_range.end >= range.end
 5152                                })
 5153                        })?;
 5154
 5155                        if all_edits_within_excerpt {
 5156                            return Ok(());
 5157                        }
 5158                    }
 5159                }
 5160            }
 5161        } else {
 5162            return Ok(());
 5163        }
 5164
 5165        let mut ranges_to_highlight = Vec::new();
 5166        let excerpt_buffer = cx.new(|cx| {
 5167            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5168            for (buffer_handle, transaction) in &entries {
 5169                let edited_ranges = buffer_handle
 5170                    .read(cx)
 5171                    .edited_ranges_for_transaction::<Point>(transaction)
 5172                    .collect::<Vec<_>>();
 5173                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5174                    PathKey::for_buffer(buffer_handle, cx),
 5175                    buffer_handle.clone(),
 5176                    edited_ranges,
 5177                    DEFAULT_MULTIBUFFER_CONTEXT,
 5178                    cx,
 5179                );
 5180
 5181                ranges_to_highlight.extend(ranges);
 5182            }
 5183            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5184            multibuffer
 5185        })?;
 5186
 5187        workspace.update_in(cx, |workspace, window, cx| {
 5188            let project = workspace.project().clone();
 5189            let editor =
 5190                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5191            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5192            editor.update(cx, |editor, cx| {
 5193                editor.highlight_background::<Self>(
 5194                    &ranges_to_highlight,
 5195                    |theme| theme.editor_highlighted_line_background,
 5196                    cx,
 5197                );
 5198            });
 5199        })?;
 5200
 5201        Ok(())
 5202    }
 5203
 5204    pub fn clear_code_action_providers(&mut self) {
 5205        self.code_action_providers.clear();
 5206        self.available_code_actions.take();
 5207    }
 5208
 5209    pub fn add_code_action_provider(
 5210        &mut self,
 5211        provider: Rc<dyn CodeActionProvider>,
 5212        window: &mut Window,
 5213        cx: &mut Context<Self>,
 5214    ) {
 5215        if self
 5216            .code_action_providers
 5217            .iter()
 5218            .any(|existing_provider| existing_provider.id() == provider.id())
 5219        {
 5220            return;
 5221        }
 5222
 5223        self.code_action_providers.push(provider);
 5224        self.refresh_code_actions(window, cx);
 5225    }
 5226
 5227    pub fn remove_code_action_provider(
 5228        &mut self,
 5229        id: Arc<str>,
 5230        window: &mut Window,
 5231        cx: &mut Context<Self>,
 5232    ) {
 5233        self.code_action_providers
 5234            .retain(|provider| provider.id() != id);
 5235        self.refresh_code_actions(window, cx);
 5236    }
 5237
 5238    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5239        let newest_selection = self.selections.newest_anchor().clone();
 5240        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5241        let buffer = self.buffer.read(cx);
 5242        if newest_selection.head().diff_base_anchor.is_some() {
 5243            return None;
 5244        }
 5245        let (start_buffer, start) =
 5246            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5247        let (end_buffer, end) =
 5248            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5249        if start_buffer != end_buffer {
 5250            return None;
 5251        }
 5252
 5253        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5254            cx.background_executor()
 5255                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5256                .await;
 5257
 5258            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5259                let providers = this.code_action_providers.clone();
 5260                let tasks = this
 5261                    .code_action_providers
 5262                    .iter()
 5263                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5264                    .collect::<Vec<_>>();
 5265                (providers, tasks)
 5266            })?;
 5267
 5268            let mut actions = Vec::new();
 5269            for (provider, provider_actions) in
 5270                providers.into_iter().zip(future::join_all(tasks).await)
 5271            {
 5272                if let Some(provider_actions) = provider_actions.log_err() {
 5273                    actions.extend(provider_actions.into_iter().map(|action| {
 5274                        AvailableCodeAction {
 5275                            excerpt_id: newest_selection.start.excerpt_id,
 5276                            action,
 5277                            provider: provider.clone(),
 5278                        }
 5279                    }));
 5280                }
 5281            }
 5282
 5283            this.update(cx, |this, cx| {
 5284                this.available_code_actions = if actions.is_empty() {
 5285                    None
 5286                } else {
 5287                    Some((
 5288                        Location {
 5289                            buffer: start_buffer,
 5290                            range: start..end,
 5291                        },
 5292                        actions.into(),
 5293                    ))
 5294                };
 5295                cx.notify();
 5296            })
 5297        }));
 5298        None
 5299    }
 5300
 5301    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5302        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5303            self.show_git_blame_inline = false;
 5304
 5305            self.show_git_blame_inline_delay_task =
 5306                Some(cx.spawn_in(window, async move |this, cx| {
 5307                    cx.background_executor().timer(delay).await;
 5308
 5309                    this.update(cx, |this, cx| {
 5310                        this.show_git_blame_inline = true;
 5311                        cx.notify();
 5312                    })
 5313                    .log_err();
 5314                }));
 5315        }
 5316    }
 5317
 5318    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5319        if self.pending_rename.is_some() {
 5320            return None;
 5321        }
 5322
 5323        let provider = self.semantics_provider.clone()?;
 5324        let buffer = self.buffer.read(cx);
 5325        let newest_selection = self.selections.newest_anchor().clone();
 5326        let cursor_position = newest_selection.head();
 5327        let (cursor_buffer, cursor_buffer_position) =
 5328            buffer.text_anchor_for_position(cursor_position, cx)?;
 5329        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5330        if cursor_buffer != tail_buffer {
 5331            return None;
 5332        }
 5333        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5334        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5335            cx.background_executor()
 5336                .timer(Duration::from_millis(debounce))
 5337                .await;
 5338
 5339            let highlights = if let Some(highlights) = cx
 5340                .update(|cx| {
 5341                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5342                })
 5343                .ok()
 5344                .flatten()
 5345            {
 5346                highlights.await.log_err()
 5347            } else {
 5348                None
 5349            };
 5350
 5351            if let Some(highlights) = highlights {
 5352                this.update(cx, |this, cx| {
 5353                    if this.pending_rename.is_some() {
 5354                        return;
 5355                    }
 5356
 5357                    let buffer_id = cursor_position.buffer_id;
 5358                    let buffer = this.buffer.read(cx);
 5359                    if !buffer
 5360                        .text_anchor_for_position(cursor_position, cx)
 5361                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5362                    {
 5363                        return;
 5364                    }
 5365
 5366                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5367                    let mut write_ranges = Vec::new();
 5368                    let mut read_ranges = Vec::new();
 5369                    for highlight in highlights {
 5370                        for (excerpt_id, excerpt_range) in
 5371                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5372                        {
 5373                            let start = highlight
 5374                                .range
 5375                                .start
 5376                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5377                            let end = highlight
 5378                                .range
 5379                                .end
 5380                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5381                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5382                                continue;
 5383                            }
 5384
 5385                            let range = Anchor {
 5386                                buffer_id,
 5387                                excerpt_id,
 5388                                text_anchor: start,
 5389                                diff_base_anchor: None,
 5390                            }..Anchor {
 5391                                buffer_id,
 5392                                excerpt_id,
 5393                                text_anchor: end,
 5394                                diff_base_anchor: None,
 5395                            };
 5396                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5397                                write_ranges.push(range);
 5398                            } else {
 5399                                read_ranges.push(range);
 5400                            }
 5401                        }
 5402                    }
 5403
 5404                    this.highlight_background::<DocumentHighlightRead>(
 5405                        &read_ranges,
 5406                        |theme| theme.editor_document_highlight_read_background,
 5407                        cx,
 5408                    );
 5409                    this.highlight_background::<DocumentHighlightWrite>(
 5410                        &write_ranges,
 5411                        |theme| theme.editor_document_highlight_write_background,
 5412                        cx,
 5413                    );
 5414                    cx.notify();
 5415                })
 5416                .log_err();
 5417            }
 5418        }));
 5419        None
 5420    }
 5421
 5422    pub fn refresh_selected_text_highlights(
 5423        &mut self,
 5424        window: &mut Window,
 5425        cx: &mut Context<Editor>,
 5426    ) {
 5427        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 5428            return;
 5429        }
 5430        self.selection_highlight_task.take();
 5431        if !EditorSettings::get_global(cx).selection_highlight {
 5432            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5433            return;
 5434        }
 5435        if self.selections.count() != 1 || self.selections.line_mode {
 5436            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5437            return;
 5438        }
 5439        let selection = self.selections.newest::<Point>(cx);
 5440        if selection.is_empty() || selection.start.row != selection.end.row {
 5441            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5442            return;
 5443        }
 5444        let debounce = EditorSettings::get_global(cx).selection_highlight_debounce;
 5445        self.selection_highlight_task = Some(cx.spawn_in(window, async move |editor, cx| {
 5446            cx.background_executor()
 5447                .timer(Duration::from_millis(debounce))
 5448                .await;
 5449            let Some(Some(matches_task)) = editor
 5450                .update_in(cx, |editor, _, cx| {
 5451                    if editor.selections.count() != 1 || editor.selections.line_mode {
 5452                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5453                        return None;
 5454                    }
 5455                    let selection = editor.selections.newest::<Point>(cx);
 5456                    if selection.is_empty() || selection.start.row != selection.end.row {
 5457                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5458                        return None;
 5459                    }
 5460                    let buffer = editor.buffer().read(cx).snapshot(cx);
 5461                    let query = buffer.text_for_range(selection.range()).collect::<String>();
 5462                    if query.trim().is_empty() {
 5463                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5464                        return None;
 5465                    }
 5466                    Some(cx.background_spawn(async move {
 5467                        let mut ranges = Vec::new();
 5468                        let selection_anchors = selection.range().to_anchors(&buffer);
 5469                        for range in [buffer.anchor_before(0)..buffer.anchor_after(buffer.len())] {
 5470                            for (search_buffer, search_range, excerpt_id) in
 5471                                buffer.range_to_buffer_ranges(range)
 5472                            {
 5473                                ranges.extend(
 5474                                    project::search::SearchQuery::text(
 5475                                        query.clone(),
 5476                                        false,
 5477                                        false,
 5478                                        false,
 5479                                        Default::default(),
 5480                                        Default::default(),
 5481                                        None,
 5482                                    )
 5483                                    .unwrap()
 5484                                    .search(search_buffer, Some(search_range.clone()))
 5485                                    .await
 5486                                    .into_iter()
 5487                                    .filter_map(
 5488                                        |match_range| {
 5489                                            let start = search_buffer.anchor_after(
 5490                                                search_range.start + match_range.start,
 5491                                            );
 5492                                            let end = search_buffer.anchor_before(
 5493                                                search_range.start + match_range.end,
 5494                                            );
 5495                                            let range = Anchor::range_in_buffer(
 5496                                                excerpt_id,
 5497                                                search_buffer.remote_id(),
 5498                                                start..end,
 5499                                            );
 5500                                            (range != selection_anchors).then_some(range)
 5501                                        },
 5502                                    ),
 5503                                );
 5504                            }
 5505                        }
 5506                        ranges
 5507                    }))
 5508                })
 5509                .log_err()
 5510            else {
 5511                return;
 5512            };
 5513            let matches = matches_task.await;
 5514            editor
 5515                .update_in(cx, |editor, _, cx| {
 5516                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5517                    if !matches.is_empty() {
 5518                        editor.highlight_background::<SelectedTextHighlight>(
 5519                            &matches,
 5520                            |theme| theme.editor_document_highlight_bracket_background,
 5521                            cx,
 5522                        )
 5523                    }
 5524                })
 5525                .log_err();
 5526        }));
 5527    }
 5528
 5529    pub fn refresh_inline_completion(
 5530        &mut self,
 5531        debounce: bool,
 5532        user_requested: bool,
 5533        window: &mut Window,
 5534        cx: &mut Context<Self>,
 5535    ) -> Option<()> {
 5536        let provider = self.edit_prediction_provider()?;
 5537        let cursor = self.selections.newest_anchor().head();
 5538        let (buffer, cursor_buffer_position) =
 5539            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5540
 5541        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 5542            self.discard_inline_completion(false, cx);
 5543            return None;
 5544        }
 5545
 5546        if !user_requested
 5547            && (!self.should_show_edit_predictions()
 5548                || !self.is_focused(window)
 5549                || buffer.read(cx).is_empty())
 5550        {
 5551            self.discard_inline_completion(false, cx);
 5552            return None;
 5553        }
 5554
 5555        self.update_visible_inline_completion(window, cx);
 5556        provider.refresh(
 5557            self.project.clone(),
 5558            buffer,
 5559            cursor_buffer_position,
 5560            debounce,
 5561            cx,
 5562        );
 5563        Some(())
 5564    }
 5565
 5566    fn show_edit_predictions_in_menu(&self) -> bool {
 5567        match self.edit_prediction_settings {
 5568            EditPredictionSettings::Disabled => false,
 5569            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 5570        }
 5571    }
 5572
 5573    pub fn edit_predictions_enabled(&self) -> bool {
 5574        match self.edit_prediction_settings {
 5575            EditPredictionSettings::Disabled => false,
 5576            EditPredictionSettings::Enabled { .. } => true,
 5577        }
 5578    }
 5579
 5580    fn edit_prediction_requires_modifier(&self) -> bool {
 5581        match self.edit_prediction_settings {
 5582            EditPredictionSettings::Disabled => false,
 5583            EditPredictionSettings::Enabled {
 5584                preview_requires_modifier,
 5585                ..
 5586            } => preview_requires_modifier,
 5587        }
 5588    }
 5589
 5590    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 5591        if self.edit_prediction_provider.is_none() {
 5592            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 5593        } else {
 5594            let selection = self.selections.newest_anchor();
 5595            let cursor = selection.head();
 5596
 5597            if let Some((buffer, cursor_buffer_position)) =
 5598                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5599            {
 5600                self.edit_prediction_settings =
 5601                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 5602            }
 5603        }
 5604    }
 5605
 5606    fn edit_prediction_settings_at_position(
 5607        &self,
 5608        buffer: &Entity<Buffer>,
 5609        buffer_position: language::Anchor,
 5610        cx: &App,
 5611    ) -> EditPredictionSettings {
 5612        if !self.mode.is_full()
 5613            || !self.show_inline_completions_override.unwrap_or(true)
 5614            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 5615        {
 5616            return EditPredictionSettings::Disabled;
 5617        }
 5618
 5619        let buffer = buffer.read(cx);
 5620
 5621        let file = buffer.file();
 5622
 5623        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 5624            return EditPredictionSettings::Disabled;
 5625        };
 5626
 5627        let by_provider = matches!(
 5628            self.menu_inline_completions_policy,
 5629            MenuInlineCompletionsPolicy::ByProvider
 5630        );
 5631
 5632        let show_in_menu = by_provider
 5633            && self
 5634                .edit_prediction_provider
 5635                .as_ref()
 5636                .map_or(false, |provider| {
 5637                    provider.provider.show_completions_in_menu()
 5638                });
 5639
 5640        let preview_requires_modifier =
 5641            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 5642
 5643        EditPredictionSettings::Enabled {
 5644            show_in_menu,
 5645            preview_requires_modifier,
 5646        }
 5647    }
 5648
 5649    fn should_show_edit_predictions(&self) -> bool {
 5650        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 5651    }
 5652
 5653    pub fn edit_prediction_preview_is_active(&self) -> bool {
 5654        matches!(
 5655            self.edit_prediction_preview,
 5656            EditPredictionPreview::Active { .. }
 5657        )
 5658    }
 5659
 5660    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 5661        let cursor = self.selections.newest_anchor().head();
 5662        if let Some((buffer, cursor_position)) =
 5663            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5664        {
 5665            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 5666        } else {
 5667            false
 5668        }
 5669    }
 5670
 5671    fn edit_predictions_enabled_in_buffer(
 5672        &self,
 5673        buffer: &Entity<Buffer>,
 5674        buffer_position: language::Anchor,
 5675        cx: &App,
 5676    ) -> bool {
 5677        maybe!({
 5678            if self.read_only(cx) {
 5679                return Some(false);
 5680            }
 5681            let provider = self.edit_prediction_provider()?;
 5682            if !provider.is_enabled(&buffer, buffer_position, cx) {
 5683                return Some(false);
 5684            }
 5685            let buffer = buffer.read(cx);
 5686            let Some(file) = buffer.file() else {
 5687                return Some(true);
 5688            };
 5689            let settings = all_language_settings(Some(file), cx);
 5690            Some(settings.edit_predictions_enabled_for_file(file, cx))
 5691        })
 5692        .unwrap_or(false)
 5693    }
 5694
 5695    fn cycle_inline_completion(
 5696        &mut self,
 5697        direction: Direction,
 5698        window: &mut Window,
 5699        cx: &mut Context<Self>,
 5700    ) -> Option<()> {
 5701        let provider = self.edit_prediction_provider()?;
 5702        let cursor = self.selections.newest_anchor().head();
 5703        let (buffer, cursor_buffer_position) =
 5704            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5705        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 5706            return None;
 5707        }
 5708
 5709        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 5710        self.update_visible_inline_completion(window, cx);
 5711
 5712        Some(())
 5713    }
 5714
 5715    pub fn show_inline_completion(
 5716        &mut self,
 5717        _: &ShowEditPrediction,
 5718        window: &mut Window,
 5719        cx: &mut Context<Self>,
 5720    ) {
 5721        if !self.has_active_inline_completion() {
 5722            self.refresh_inline_completion(false, true, window, cx);
 5723            return;
 5724        }
 5725
 5726        self.update_visible_inline_completion(window, cx);
 5727    }
 5728
 5729    pub fn display_cursor_names(
 5730        &mut self,
 5731        _: &DisplayCursorNames,
 5732        window: &mut Window,
 5733        cx: &mut Context<Self>,
 5734    ) {
 5735        self.show_cursor_names(window, cx);
 5736    }
 5737
 5738    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5739        self.show_cursor_names = true;
 5740        cx.notify();
 5741        cx.spawn_in(window, async move |this, cx| {
 5742            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 5743            this.update(cx, |this, cx| {
 5744                this.show_cursor_names = false;
 5745                cx.notify()
 5746            })
 5747            .ok()
 5748        })
 5749        .detach();
 5750    }
 5751
 5752    pub fn next_edit_prediction(
 5753        &mut self,
 5754        _: &NextEditPrediction,
 5755        window: &mut Window,
 5756        cx: &mut Context<Self>,
 5757    ) {
 5758        if self.has_active_inline_completion() {
 5759            self.cycle_inline_completion(Direction::Next, window, cx);
 5760        } else {
 5761            let is_copilot_disabled = self
 5762                .refresh_inline_completion(false, true, window, cx)
 5763                .is_none();
 5764            if is_copilot_disabled {
 5765                cx.propagate();
 5766            }
 5767        }
 5768    }
 5769
 5770    pub fn previous_edit_prediction(
 5771        &mut self,
 5772        _: &PreviousEditPrediction,
 5773        window: &mut Window,
 5774        cx: &mut Context<Self>,
 5775    ) {
 5776        if self.has_active_inline_completion() {
 5777            self.cycle_inline_completion(Direction::Prev, window, cx);
 5778        } else {
 5779            let is_copilot_disabled = self
 5780                .refresh_inline_completion(false, true, window, cx)
 5781                .is_none();
 5782            if is_copilot_disabled {
 5783                cx.propagate();
 5784            }
 5785        }
 5786    }
 5787
 5788    pub fn accept_edit_prediction(
 5789        &mut self,
 5790        _: &AcceptEditPrediction,
 5791        window: &mut Window,
 5792        cx: &mut Context<Self>,
 5793    ) {
 5794        if self.show_edit_predictions_in_menu() {
 5795            self.hide_context_menu(window, cx);
 5796        }
 5797
 5798        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5799            return;
 5800        };
 5801
 5802        self.report_inline_completion_event(
 5803            active_inline_completion.completion_id.clone(),
 5804            true,
 5805            cx,
 5806        );
 5807
 5808        match &active_inline_completion.completion {
 5809            InlineCompletion::Move { target, .. } => {
 5810                let target = *target;
 5811
 5812                if let Some(position_map) = &self.last_position_map {
 5813                    if position_map
 5814                        .visible_row_range
 5815                        .contains(&target.to_display_point(&position_map.snapshot).row())
 5816                        || !self.edit_prediction_requires_modifier()
 5817                    {
 5818                        self.unfold_ranges(&[target..target], true, false, cx);
 5819                        // Note that this is also done in vim's handler of the Tab action.
 5820                        self.change_selections(
 5821                            Some(Autoscroll::newest()),
 5822                            window,
 5823                            cx,
 5824                            |selections| {
 5825                                selections.select_anchor_ranges([target..target]);
 5826                            },
 5827                        );
 5828                        self.clear_row_highlights::<EditPredictionPreview>();
 5829
 5830                        self.edit_prediction_preview
 5831                            .set_previous_scroll_position(None);
 5832                    } else {
 5833                        self.edit_prediction_preview
 5834                            .set_previous_scroll_position(Some(
 5835                                position_map.snapshot.scroll_anchor,
 5836                            ));
 5837
 5838                        self.highlight_rows::<EditPredictionPreview>(
 5839                            target..target,
 5840                            cx.theme().colors().editor_highlighted_line_background,
 5841                            true,
 5842                            cx,
 5843                        );
 5844                        self.request_autoscroll(Autoscroll::fit(), cx);
 5845                    }
 5846                }
 5847            }
 5848            InlineCompletion::Edit { edits, .. } => {
 5849                if let Some(provider) = self.edit_prediction_provider() {
 5850                    provider.accept(cx);
 5851                }
 5852
 5853                let snapshot = self.buffer.read(cx).snapshot(cx);
 5854                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 5855
 5856                self.buffer.update(cx, |buffer, cx| {
 5857                    buffer.edit(edits.iter().cloned(), None, cx)
 5858                });
 5859
 5860                self.change_selections(None, window, cx, |s| {
 5861                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 5862                });
 5863
 5864                self.update_visible_inline_completion(window, cx);
 5865                if self.active_inline_completion.is_none() {
 5866                    self.refresh_inline_completion(true, true, window, cx);
 5867                }
 5868
 5869                cx.notify();
 5870            }
 5871        }
 5872
 5873        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 5874    }
 5875
 5876    pub fn accept_partial_inline_completion(
 5877        &mut self,
 5878        _: &AcceptPartialEditPrediction,
 5879        window: &mut Window,
 5880        cx: &mut Context<Self>,
 5881    ) {
 5882        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5883            return;
 5884        };
 5885        if self.selections.count() != 1 {
 5886            return;
 5887        }
 5888
 5889        self.report_inline_completion_event(
 5890            active_inline_completion.completion_id.clone(),
 5891            true,
 5892            cx,
 5893        );
 5894
 5895        match &active_inline_completion.completion {
 5896            InlineCompletion::Move { target, .. } => {
 5897                let target = *target;
 5898                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 5899                    selections.select_anchor_ranges([target..target]);
 5900                });
 5901            }
 5902            InlineCompletion::Edit { edits, .. } => {
 5903                // Find an insertion that starts at the cursor position.
 5904                let snapshot = self.buffer.read(cx).snapshot(cx);
 5905                let cursor_offset = self.selections.newest::<usize>(cx).head();
 5906                let insertion = edits.iter().find_map(|(range, text)| {
 5907                    let range = range.to_offset(&snapshot);
 5908                    if range.is_empty() && range.start == cursor_offset {
 5909                        Some(text)
 5910                    } else {
 5911                        None
 5912                    }
 5913                });
 5914
 5915                if let Some(text) = insertion {
 5916                    let mut partial_completion = text
 5917                        .chars()
 5918                        .by_ref()
 5919                        .take_while(|c| c.is_alphabetic())
 5920                        .collect::<String>();
 5921                    if partial_completion.is_empty() {
 5922                        partial_completion = text
 5923                            .chars()
 5924                            .by_ref()
 5925                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 5926                            .collect::<String>();
 5927                    }
 5928
 5929                    cx.emit(EditorEvent::InputHandled {
 5930                        utf16_range_to_replace: None,
 5931                        text: partial_completion.clone().into(),
 5932                    });
 5933
 5934                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 5935
 5936                    self.refresh_inline_completion(true, true, window, cx);
 5937                    cx.notify();
 5938                } else {
 5939                    self.accept_edit_prediction(&Default::default(), window, cx);
 5940                }
 5941            }
 5942        }
 5943    }
 5944
 5945    fn discard_inline_completion(
 5946        &mut self,
 5947        should_report_inline_completion_event: bool,
 5948        cx: &mut Context<Self>,
 5949    ) -> bool {
 5950        if should_report_inline_completion_event {
 5951            let completion_id = self
 5952                .active_inline_completion
 5953                .as_ref()
 5954                .and_then(|active_completion| active_completion.completion_id.clone());
 5955
 5956            self.report_inline_completion_event(completion_id, false, cx);
 5957        }
 5958
 5959        if let Some(provider) = self.edit_prediction_provider() {
 5960            provider.discard(cx);
 5961        }
 5962
 5963        self.take_active_inline_completion(cx)
 5964    }
 5965
 5966    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 5967        let Some(provider) = self.edit_prediction_provider() else {
 5968            return;
 5969        };
 5970
 5971        let Some((_, buffer, _)) = self
 5972            .buffer
 5973            .read(cx)
 5974            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 5975        else {
 5976            return;
 5977        };
 5978
 5979        let extension = buffer
 5980            .read(cx)
 5981            .file()
 5982            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 5983
 5984        let event_type = match accepted {
 5985            true => "Edit Prediction Accepted",
 5986            false => "Edit Prediction Discarded",
 5987        };
 5988        telemetry::event!(
 5989            event_type,
 5990            provider = provider.name(),
 5991            prediction_id = id,
 5992            suggestion_accepted = accepted,
 5993            file_extension = extension,
 5994        );
 5995    }
 5996
 5997    pub fn has_active_inline_completion(&self) -> bool {
 5998        self.active_inline_completion.is_some()
 5999    }
 6000
 6001    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6002        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6003            return false;
 6004        };
 6005
 6006        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6007        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6008        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6009        true
 6010    }
 6011
 6012    /// Returns true when we're displaying the edit prediction popover below the cursor
 6013    /// like we are not previewing and the LSP autocomplete menu is visible
 6014    /// or we are in `when_holding_modifier` mode.
 6015    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6016        if self.edit_prediction_preview_is_active()
 6017            || !self.show_edit_predictions_in_menu()
 6018            || !self.edit_predictions_enabled()
 6019        {
 6020            return false;
 6021        }
 6022
 6023        if self.has_visible_completions_menu() {
 6024            return true;
 6025        }
 6026
 6027        has_completion && self.edit_prediction_requires_modifier()
 6028    }
 6029
 6030    fn handle_modifiers_changed(
 6031        &mut self,
 6032        modifiers: Modifiers,
 6033        position_map: &PositionMap,
 6034        window: &mut Window,
 6035        cx: &mut Context<Self>,
 6036    ) {
 6037        if self.show_edit_predictions_in_menu() {
 6038            self.update_edit_prediction_preview(&modifiers, window, cx);
 6039        }
 6040
 6041        self.update_selection_mode(&modifiers, position_map, window, cx);
 6042
 6043        let mouse_position = window.mouse_position();
 6044        if !position_map.text_hitbox.is_hovered(window) {
 6045            return;
 6046        }
 6047
 6048        self.update_hovered_link(
 6049            position_map.point_for_position(mouse_position),
 6050            &position_map.snapshot,
 6051            modifiers,
 6052            window,
 6053            cx,
 6054        )
 6055    }
 6056
 6057    fn update_selection_mode(
 6058        &mut self,
 6059        modifiers: &Modifiers,
 6060        position_map: &PositionMap,
 6061        window: &mut Window,
 6062        cx: &mut Context<Self>,
 6063    ) {
 6064        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6065            return;
 6066        }
 6067
 6068        let mouse_position = window.mouse_position();
 6069        let point_for_position = position_map.point_for_position(mouse_position);
 6070        let position = point_for_position.previous_valid;
 6071
 6072        self.select(
 6073            SelectPhase::BeginColumnar {
 6074                position,
 6075                reset: false,
 6076                goal_column: point_for_position.exact_unclipped.column(),
 6077            },
 6078            window,
 6079            cx,
 6080        );
 6081    }
 6082
 6083    fn update_edit_prediction_preview(
 6084        &mut self,
 6085        modifiers: &Modifiers,
 6086        window: &mut Window,
 6087        cx: &mut Context<Self>,
 6088    ) {
 6089        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6090        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6091            return;
 6092        };
 6093
 6094        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6095            if matches!(
 6096                self.edit_prediction_preview,
 6097                EditPredictionPreview::Inactive { .. }
 6098            ) {
 6099                self.edit_prediction_preview = EditPredictionPreview::Active {
 6100                    previous_scroll_position: None,
 6101                    since: Instant::now(),
 6102                };
 6103
 6104                self.update_visible_inline_completion(window, cx);
 6105                cx.notify();
 6106            }
 6107        } else if let EditPredictionPreview::Active {
 6108            previous_scroll_position,
 6109            since,
 6110        } = self.edit_prediction_preview
 6111        {
 6112            if let (Some(previous_scroll_position), Some(position_map)) =
 6113                (previous_scroll_position, self.last_position_map.as_ref())
 6114            {
 6115                self.set_scroll_position(
 6116                    previous_scroll_position
 6117                        .scroll_position(&position_map.snapshot.display_snapshot),
 6118                    window,
 6119                    cx,
 6120                );
 6121            }
 6122
 6123            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6124                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6125            };
 6126            self.clear_row_highlights::<EditPredictionPreview>();
 6127            self.update_visible_inline_completion(window, cx);
 6128            cx.notify();
 6129        }
 6130    }
 6131
 6132    fn update_visible_inline_completion(
 6133        &mut self,
 6134        _window: &mut Window,
 6135        cx: &mut Context<Self>,
 6136    ) -> Option<()> {
 6137        let selection = self.selections.newest_anchor();
 6138        let cursor = selection.head();
 6139        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6140        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6141        let excerpt_id = cursor.excerpt_id;
 6142
 6143        let show_in_menu = self.show_edit_predictions_in_menu();
 6144        let completions_menu_has_precedence = !show_in_menu
 6145            && (self.context_menu.borrow().is_some()
 6146                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6147
 6148        if completions_menu_has_precedence
 6149            || !offset_selection.is_empty()
 6150            || self
 6151                .active_inline_completion
 6152                .as_ref()
 6153                .map_or(false, |completion| {
 6154                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6155                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6156                    !invalidation_range.contains(&offset_selection.head())
 6157                })
 6158        {
 6159            self.discard_inline_completion(false, cx);
 6160            return None;
 6161        }
 6162
 6163        self.take_active_inline_completion(cx);
 6164        let Some(provider) = self.edit_prediction_provider() else {
 6165            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6166            return None;
 6167        };
 6168
 6169        let (buffer, cursor_buffer_position) =
 6170            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6171
 6172        self.edit_prediction_settings =
 6173            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6174
 6175        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6176
 6177        if self.edit_prediction_indent_conflict {
 6178            let cursor_point = cursor.to_point(&multibuffer);
 6179
 6180            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6181
 6182            if let Some((_, indent)) = indents.iter().next() {
 6183                if indent.len == cursor_point.column {
 6184                    self.edit_prediction_indent_conflict = false;
 6185                }
 6186            }
 6187        }
 6188
 6189        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6190        let edits = inline_completion
 6191            .edits
 6192            .into_iter()
 6193            .flat_map(|(range, new_text)| {
 6194                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6195                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6196                Some((start..end, new_text))
 6197            })
 6198            .collect::<Vec<_>>();
 6199        if edits.is_empty() {
 6200            return None;
 6201        }
 6202
 6203        let first_edit_start = edits.first().unwrap().0.start;
 6204        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6205        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6206
 6207        let last_edit_end = edits.last().unwrap().0.end;
 6208        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6209        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6210
 6211        let cursor_row = cursor.to_point(&multibuffer).row;
 6212
 6213        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6214
 6215        let mut inlay_ids = Vec::new();
 6216        let invalidation_row_range;
 6217        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6218            Some(cursor_row..edit_end_row)
 6219        } else if cursor_row > edit_end_row {
 6220            Some(edit_start_row..cursor_row)
 6221        } else {
 6222            None
 6223        };
 6224        let is_move =
 6225            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6226        let completion = if is_move {
 6227            invalidation_row_range =
 6228                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6229            let target = first_edit_start;
 6230            InlineCompletion::Move { target, snapshot }
 6231        } else {
 6232            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6233                && !self.inline_completions_hidden_for_vim_mode;
 6234
 6235            if show_completions_in_buffer {
 6236                if edits
 6237                    .iter()
 6238                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6239                {
 6240                    let mut inlays = Vec::new();
 6241                    for (range, new_text) in &edits {
 6242                        let inlay = Inlay::inline_completion(
 6243                            post_inc(&mut self.next_inlay_id),
 6244                            range.start,
 6245                            new_text.as_str(),
 6246                        );
 6247                        inlay_ids.push(inlay.id);
 6248                        inlays.push(inlay);
 6249                    }
 6250
 6251                    self.splice_inlays(&[], inlays, cx);
 6252                } else {
 6253                    let background_color = cx.theme().status().deleted_background;
 6254                    self.highlight_text::<InlineCompletionHighlight>(
 6255                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6256                        HighlightStyle {
 6257                            background_color: Some(background_color),
 6258                            ..Default::default()
 6259                        },
 6260                        cx,
 6261                    );
 6262                }
 6263            }
 6264
 6265            invalidation_row_range = edit_start_row..edit_end_row;
 6266
 6267            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6268                if provider.show_tab_accept_marker() {
 6269                    EditDisplayMode::TabAccept
 6270                } else {
 6271                    EditDisplayMode::Inline
 6272                }
 6273            } else {
 6274                EditDisplayMode::DiffPopover
 6275            };
 6276
 6277            InlineCompletion::Edit {
 6278                edits,
 6279                edit_preview: inline_completion.edit_preview,
 6280                display_mode,
 6281                snapshot,
 6282            }
 6283        };
 6284
 6285        let invalidation_range = multibuffer
 6286            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6287            ..multibuffer.anchor_after(Point::new(
 6288                invalidation_row_range.end,
 6289                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6290            ));
 6291
 6292        self.stale_inline_completion_in_menu = None;
 6293        self.active_inline_completion = Some(InlineCompletionState {
 6294            inlay_ids,
 6295            completion,
 6296            completion_id: inline_completion.id,
 6297            invalidation_range,
 6298        });
 6299
 6300        cx.notify();
 6301
 6302        Some(())
 6303    }
 6304
 6305    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6306        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6307    }
 6308
 6309    fn render_code_actions_indicator(
 6310        &self,
 6311        _style: &EditorStyle,
 6312        row: DisplayRow,
 6313        is_active: bool,
 6314        breakpoint: Option<&(Anchor, Breakpoint)>,
 6315        cx: &mut Context<Self>,
 6316    ) -> Option<IconButton> {
 6317        let color = Color::Muted;
 6318        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6319        let show_tooltip = !self.context_menu_visible();
 6320
 6321        if self.available_code_actions.is_some() {
 6322            Some(
 6323                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 6324                    .shape(ui::IconButtonShape::Square)
 6325                    .icon_size(IconSize::XSmall)
 6326                    .icon_color(color)
 6327                    .toggle_state(is_active)
 6328                    .when(show_tooltip, |this| {
 6329                        this.tooltip({
 6330                            let focus_handle = self.focus_handle.clone();
 6331                            move |window, cx| {
 6332                                Tooltip::for_action_in(
 6333                                    "Toggle Code Actions",
 6334                                    &ToggleCodeActions {
 6335                                        deployed_from_indicator: None,
 6336                                    },
 6337                                    &focus_handle,
 6338                                    window,
 6339                                    cx,
 6340                                )
 6341                            }
 6342                        })
 6343                    })
 6344                    .on_click(cx.listener(move |editor, _e, window, cx| {
 6345                        window.focus(&editor.focus_handle(cx));
 6346                        editor.toggle_code_actions(
 6347                            &ToggleCodeActions {
 6348                                deployed_from_indicator: Some(row),
 6349                            },
 6350                            window,
 6351                            cx,
 6352                        );
 6353                    }))
 6354                    .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6355                        editor.set_breakpoint_context_menu(
 6356                            row,
 6357                            position,
 6358                            event.down.position,
 6359                            window,
 6360                            cx,
 6361                        );
 6362                    })),
 6363            )
 6364        } else {
 6365            None
 6366        }
 6367    }
 6368
 6369    fn clear_tasks(&mut self) {
 6370        self.tasks.clear()
 6371    }
 6372
 6373    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6374        if self.tasks.insert(key, value).is_some() {
 6375            // This case should hopefully be rare, but just in case...
 6376            log::error!(
 6377                "multiple different run targets found on a single line, only the last target will be rendered"
 6378            )
 6379        }
 6380    }
 6381
 6382    /// Get all display points of breakpoints that will be rendered within editor
 6383    ///
 6384    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6385    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6386    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6387    fn active_breakpoints(
 6388        &self,
 6389        range: Range<DisplayRow>,
 6390        window: &mut Window,
 6391        cx: &mut Context<Self>,
 6392    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 6393        let mut breakpoint_display_points = HashMap::default();
 6394
 6395        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 6396            return breakpoint_display_points;
 6397        };
 6398
 6399        let snapshot = self.snapshot(window, cx);
 6400
 6401        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 6402        let Some(project) = self.project.as_ref() else {
 6403            return breakpoint_display_points;
 6404        };
 6405
 6406        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 6407            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 6408
 6409        for (buffer_snapshot, range, excerpt_id) in
 6410            multi_buffer_snapshot.range_to_buffer_ranges(range)
 6411        {
 6412            let Some(buffer) = project.read_with(cx, |this, cx| {
 6413                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 6414            }) else {
 6415                continue;
 6416            };
 6417            let breakpoints = breakpoint_store.read(cx).breakpoints(
 6418                &buffer,
 6419                Some(
 6420                    buffer_snapshot.anchor_before(range.start)
 6421                        ..buffer_snapshot.anchor_after(range.end),
 6422                ),
 6423                buffer_snapshot,
 6424                cx,
 6425            );
 6426            for (anchor, breakpoint) in breakpoints {
 6427                let multi_buffer_anchor =
 6428                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 6429                let position = multi_buffer_anchor
 6430                    .to_point(&multi_buffer_snapshot)
 6431                    .to_display_point(&snapshot);
 6432
 6433                breakpoint_display_points
 6434                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 6435            }
 6436        }
 6437
 6438        breakpoint_display_points
 6439    }
 6440
 6441    fn breakpoint_context_menu(
 6442        &self,
 6443        anchor: Anchor,
 6444        window: &mut Window,
 6445        cx: &mut Context<Self>,
 6446    ) -> Entity<ui::ContextMenu> {
 6447        let weak_editor = cx.weak_entity();
 6448        let focus_handle = self.focus_handle(cx);
 6449
 6450        let row = self
 6451            .buffer
 6452            .read(cx)
 6453            .snapshot(cx)
 6454            .summary_for_anchor::<Point>(&anchor)
 6455            .row;
 6456
 6457        let breakpoint = self
 6458            .breakpoint_at_row(row, window, cx)
 6459            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 6460
 6461        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 6462            "Edit Log Breakpoint"
 6463        } else {
 6464            "Set Log Breakpoint"
 6465        };
 6466
 6467        let condition_breakpoint_msg = if breakpoint
 6468            .as_ref()
 6469            .is_some_and(|bp| bp.1.condition.is_some())
 6470        {
 6471            "Edit Condition Breakpoint"
 6472        } else {
 6473            "Set Condition Breakpoint"
 6474        };
 6475
 6476        let hit_condition_breakpoint_msg = if breakpoint
 6477            .as_ref()
 6478            .is_some_and(|bp| bp.1.hit_condition.is_some())
 6479        {
 6480            "Edit Hit Condition Breakpoint"
 6481        } else {
 6482            "Set Hit Condition Breakpoint"
 6483        };
 6484
 6485        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 6486            "Unset Breakpoint"
 6487        } else {
 6488            "Set Breakpoint"
 6489        };
 6490
 6491        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 6492            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 6493
 6494        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 6495            BreakpointState::Enabled => Some("Disable"),
 6496            BreakpointState::Disabled => Some("Enable"),
 6497        });
 6498
 6499        let (anchor, breakpoint) =
 6500            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 6501
 6502        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 6503            menu.on_blur_subscription(Subscription::new(|| {}))
 6504                .context(focus_handle)
 6505                .when(run_to_cursor, |this| {
 6506                    let weak_editor = weak_editor.clone();
 6507                    this.entry("Run to cursor", None, move |window, cx| {
 6508                        weak_editor
 6509                            .update(cx, |editor, cx| {
 6510                                editor.change_selections(None, window, cx, |s| {
 6511                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 6512                                });
 6513                            })
 6514                            .ok();
 6515
 6516                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 6517                    })
 6518                    .separator()
 6519                })
 6520                .when_some(toggle_state_msg, |this, msg| {
 6521                    this.entry(msg, None, {
 6522                        let weak_editor = weak_editor.clone();
 6523                        let breakpoint = breakpoint.clone();
 6524                        move |_window, cx| {
 6525                            weak_editor
 6526                                .update(cx, |this, cx| {
 6527                                    this.edit_breakpoint_at_anchor(
 6528                                        anchor,
 6529                                        breakpoint.as_ref().clone(),
 6530                                        BreakpointEditAction::InvertState,
 6531                                        cx,
 6532                                    );
 6533                                })
 6534                                .log_err();
 6535                        }
 6536                    })
 6537                })
 6538                .entry(set_breakpoint_msg, None, {
 6539                    let weak_editor = weak_editor.clone();
 6540                    let breakpoint = breakpoint.clone();
 6541                    move |_window, cx| {
 6542                        weak_editor
 6543                            .update(cx, |this, cx| {
 6544                                this.edit_breakpoint_at_anchor(
 6545                                    anchor,
 6546                                    breakpoint.as_ref().clone(),
 6547                                    BreakpointEditAction::Toggle,
 6548                                    cx,
 6549                                );
 6550                            })
 6551                            .log_err();
 6552                    }
 6553                })
 6554                .entry(log_breakpoint_msg, None, {
 6555                    let breakpoint = breakpoint.clone();
 6556                    let weak_editor = weak_editor.clone();
 6557                    move |window, cx| {
 6558                        weak_editor
 6559                            .update(cx, |this, cx| {
 6560                                this.add_edit_breakpoint_block(
 6561                                    anchor,
 6562                                    breakpoint.as_ref(),
 6563                                    BreakpointPromptEditAction::Log,
 6564                                    window,
 6565                                    cx,
 6566                                );
 6567                            })
 6568                            .log_err();
 6569                    }
 6570                })
 6571                .entry(condition_breakpoint_msg, None, {
 6572                    let breakpoint = breakpoint.clone();
 6573                    let weak_editor = weak_editor.clone();
 6574                    move |window, cx| {
 6575                        weak_editor
 6576                            .update(cx, |this, cx| {
 6577                                this.add_edit_breakpoint_block(
 6578                                    anchor,
 6579                                    breakpoint.as_ref(),
 6580                                    BreakpointPromptEditAction::Condition,
 6581                                    window,
 6582                                    cx,
 6583                                );
 6584                            })
 6585                            .log_err();
 6586                    }
 6587                })
 6588                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 6589                    weak_editor
 6590                        .update(cx, |this, cx| {
 6591                            this.add_edit_breakpoint_block(
 6592                                anchor,
 6593                                breakpoint.as_ref(),
 6594                                BreakpointPromptEditAction::HitCondition,
 6595                                window,
 6596                                cx,
 6597                            );
 6598                        })
 6599                        .log_err();
 6600                })
 6601        })
 6602    }
 6603
 6604    fn render_breakpoint(
 6605        &self,
 6606        position: Anchor,
 6607        row: DisplayRow,
 6608        breakpoint: &Breakpoint,
 6609        cx: &mut Context<Self>,
 6610    ) -> IconButton {
 6611        let (color, icon) = {
 6612            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 6613                (false, false) => ui::IconName::DebugBreakpoint,
 6614                (true, false) => ui::IconName::DebugLogBreakpoint,
 6615                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 6616                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 6617            };
 6618
 6619            let color = if self
 6620                .gutter_breakpoint_indicator
 6621                .0
 6622                .is_some_and(|(point, is_visible)| is_visible && point.row() == row)
 6623            {
 6624                Color::Hint
 6625            } else {
 6626                Color::Debugger
 6627            };
 6628
 6629            (color, icon)
 6630        };
 6631
 6632        let breakpoint = Arc::from(breakpoint.clone());
 6633
 6634        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 6635            .icon_size(IconSize::XSmall)
 6636            .size(ui::ButtonSize::None)
 6637            .icon_color(color)
 6638            .style(ButtonStyle::Transparent)
 6639            .on_click(cx.listener({
 6640                let breakpoint = breakpoint.clone();
 6641
 6642                move |editor, event: &ClickEvent, window, cx| {
 6643                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 6644                        BreakpointEditAction::InvertState
 6645                    } else {
 6646                        BreakpointEditAction::Toggle
 6647                    };
 6648
 6649                    window.focus(&editor.focus_handle(cx));
 6650                    editor.edit_breakpoint_at_anchor(
 6651                        position,
 6652                        breakpoint.as_ref().clone(),
 6653                        edit_action,
 6654                        cx,
 6655                    );
 6656                }
 6657            }))
 6658            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6659                editor.set_breakpoint_context_menu(
 6660                    row,
 6661                    Some(position),
 6662                    event.down.position,
 6663                    window,
 6664                    cx,
 6665                );
 6666            }))
 6667    }
 6668
 6669    fn build_tasks_context(
 6670        project: &Entity<Project>,
 6671        buffer: &Entity<Buffer>,
 6672        buffer_row: u32,
 6673        tasks: &Arc<RunnableTasks>,
 6674        cx: &mut Context<Self>,
 6675    ) -> Task<Option<task::TaskContext>> {
 6676        let position = Point::new(buffer_row, tasks.column);
 6677        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 6678        let location = Location {
 6679            buffer: buffer.clone(),
 6680            range: range_start..range_start,
 6681        };
 6682        // Fill in the environmental variables from the tree-sitter captures
 6683        let mut captured_task_variables = TaskVariables::default();
 6684        for (capture_name, value) in tasks.extra_variables.clone() {
 6685            captured_task_variables.insert(
 6686                task::VariableName::Custom(capture_name.into()),
 6687                value.clone(),
 6688            );
 6689        }
 6690        project.update(cx, |project, cx| {
 6691            project.task_store().update(cx, |task_store, cx| {
 6692                task_store.task_context_for_location(captured_task_variables, location, cx)
 6693            })
 6694        })
 6695    }
 6696
 6697    pub fn spawn_nearest_task(
 6698        &mut self,
 6699        action: &SpawnNearestTask,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        let Some((workspace, _)) = self.workspace.clone() else {
 6704            return;
 6705        };
 6706        let Some(project) = self.project.clone() else {
 6707            return;
 6708        };
 6709
 6710        // Try to find a closest, enclosing node using tree-sitter that has a
 6711        // task
 6712        let Some((buffer, buffer_row, tasks)) = self
 6713            .find_enclosing_node_task(cx)
 6714            // Or find the task that's closest in row-distance.
 6715            .or_else(|| self.find_closest_task(cx))
 6716        else {
 6717            return;
 6718        };
 6719
 6720        let reveal_strategy = action.reveal;
 6721        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6722        cx.spawn_in(window, async move |_, cx| {
 6723            let context = task_context.await?;
 6724            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 6725
 6726            let resolved = resolved_task.resolved.as_mut()?;
 6727            resolved.reveal = reveal_strategy;
 6728
 6729            workspace
 6730                .update(cx, |workspace, cx| {
 6731                    workspace::tasks::schedule_resolved_task(
 6732                        workspace,
 6733                        task_source_kind,
 6734                        resolved_task,
 6735                        false,
 6736                        cx,
 6737                    );
 6738                })
 6739                .ok()
 6740        })
 6741        .detach();
 6742    }
 6743
 6744    fn find_closest_task(
 6745        &mut self,
 6746        cx: &mut Context<Self>,
 6747    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6748        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 6749
 6750        let ((buffer_id, row), tasks) = self
 6751            .tasks
 6752            .iter()
 6753            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 6754
 6755        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 6756        let tasks = Arc::new(tasks.to_owned());
 6757        Some((buffer, *row, tasks))
 6758    }
 6759
 6760    fn find_enclosing_node_task(
 6761        &mut self,
 6762        cx: &mut Context<Self>,
 6763    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6764        let snapshot = self.buffer.read(cx).snapshot(cx);
 6765        let offset = self.selections.newest::<usize>(cx).head();
 6766        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 6767        let buffer_id = excerpt.buffer().remote_id();
 6768
 6769        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 6770        let mut cursor = layer.node().walk();
 6771
 6772        while cursor.goto_first_child_for_byte(offset).is_some() {
 6773            if cursor.node().end_byte() == offset {
 6774                cursor.goto_next_sibling();
 6775            }
 6776        }
 6777
 6778        // Ascend to the smallest ancestor that contains the range and has a task.
 6779        loop {
 6780            let node = cursor.node();
 6781            let node_range = node.byte_range();
 6782            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 6783
 6784            // Check if this node contains our offset
 6785            if node_range.start <= offset && node_range.end >= offset {
 6786                // If it contains offset, check for task
 6787                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 6788                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 6789                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 6790                }
 6791            }
 6792
 6793            if !cursor.goto_parent() {
 6794                break;
 6795            }
 6796        }
 6797        None
 6798    }
 6799
 6800    fn render_run_indicator(
 6801        &self,
 6802        _style: &EditorStyle,
 6803        is_active: bool,
 6804        row: DisplayRow,
 6805        breakpoint: Option<(Anchor, Breakpoint)>,
 6806        cx: &mut Context<Self>,
 6807    ) -> IconButton {
 6808        let color = Color::Muted;
 6809        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6810
 6811        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 6812            .shape(ui::IconButtonShape::Square)
 6813            .icon_size(IconSize::XSmall)
 6814            .icon_color(color)
 6815            .toggle_state(is_active)
 6816            .on_click(cx.listener(move |editor, _e, window, cx| {
 6817                window.focus(&editor.focus_handle(cx));
 6818                editor.toggle_code_actions(
 6819                    &ToggleCodeActions {
 6820                        deployed_from_indicator: Some(row),
 6821                    },
 6822                    window,
 6823                    cx,
 6824                );
 6825            }))
 6826            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6827                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 6828            }))
 6829    }
 6830
 6831    pub fn context_menu_visible(&self) -> bool {
 6832        !self.edit_prediction_preview_is_active()
 6833            && self
 6834                .context_menu
 6835                .borrow()
 6836                .as_ref()
 6837                .map_or(false, |menu| menu.visible())
 6838    }
 6839
 6840    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 6841        self.context_menu
 6842            .borrow()
 6843            .as_ref()
 6844            .map(|menu| menu.origin())
 6845    }
 6846
 6847    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 6848        self.context_menu_options = Some(options);
 6849    }
 6850
 6851    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 6852    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 6853
 6854    fn render_edit_prediction_popover(
 6855        &mut self,
 6856        text_bounds: &Bounds<Pixels>,
 6857        content_origin: gpui::Point<Pixels>,
 6858        editor_snapshot: &EditorSnapshot,
 6859        visible_row_range: Range<DisplayRow>,
 6860        scroll_top: f32,
 6861        scroll_bottom: f32,
 6862        line_layouts: &[LineWithInvisibles],
 6863        line_height: Pixels,
 6864        scroll_pixel_position: gpui::Point<Pixels>,
 6865        newest_selection_head: Option<DisplayPoint>,
 6866        editor_width: Pixels,
 6867        style: &EditorStyle,
 6868        window: &mut Window,
 6869        cx: &mut App,
 6870    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6871        let active_inline_completion = self.active_inline_completion.as_ref()?;
 6872
 6873        if self.edit_prediction_visible_in_cursor_popover(true) {
 6874            return None;
 6875        }
 6876
 6877        match &active_inline_completion.completion {
 6878            InlineCompletion::Move { target, .. } => {
 6879                let target_display_point = target.to_display_point(editor_snapshot);
 6880
 6881                if self.edit_prediction_requires_modifier() {
 6882                    if !self.edit_prediction_preview_is_active() {
 6883                        return None;
 6884                    }
 6885
 6886                    self.render_edit_prediction_modifier_jump_popover(
 6887                        text_bounds,
 6888                        content_origin,
 6889                        visible_row_range,
 6890                        line_layouts,
 6891                        line_height,
 6892                        scroll_pixel_position,
 6893                        newest_selection_head,
 6894                        target_display_point,
 6895                        window,
 6896                        cx,
 6897                    )
 6898                } else {
 6899                    self.render_edit_prediction_eager_jump_popover(
 6900                        text_bounds,
 6901                        content_origin,
 6902                        editor_snapshot,
 6903                        visible_row_range,
 6904                        scroll_top,
 6905                        scroll_bottom,
 6906                        line_height,
 6907                        scroll_pixel_position,
 6908                        target_display_point,
 6909                        editor_width,
 6910                        window,
 6911                        cx,
 6912                    )
 6913                }
 6914            }
 6915            InlineCompletion::Edit {
 6916                display_mode: EditDisplayMode::Inline,
 6917                ..
 6918            } => None,
 6919            InlineCompletion::Edit {
 6920                display_mode: EditDisplayMode::TabAccept,
 6921                edits,
 6922                ..
 6923            } => {
 6924                let range = &edits.first()?.0;
 6925                let target_display_point = range.end.to_display_point(editor_snapshot);
 6926
 6927                self.render_edit_prediction_end_of_line_popover(
 6928                    "Accept",
 6929                    editor_snapshot,
 6930                    visible_row_range,
 6931                    target_display_point,
 6932                    line_height,
 6933                    scroll_pixel_position,
 6934                    content_origin,
 6935                    editor_width,
 6936                    window,
 6937                    cx,
 6938                )
 6939            }
 6940            InlineCompletion::Edit {
 6941                edits,
 6942                edit_preview,
 6943                display_mode: EditDisplayMode::DiffPopover,
 6944                snapshot,
 6945            } => self.render_edit_prediction_diff_popover(
 6946                text_bounds,
 6947                content_origin,
 6948                editor_snapshot,
 6949                visible_row_range,
 6950                line_layouts,
 6951                line_height,
 6952                scroll_pixel_position,
 6953                newest_selection_head,
 6954                editor_width,
 6955                style,
 6956                edits,
 6957                edit_preview,
 6958                snapshot,
 6959                window,
 6960                cx,
 6961            ),
 6962        }
 6963    }
 6964
 6965    fn render_edit_prediction_modifier_jump_popover(
 6966        &mut self,
 6967        text_bounds: &Bounds<Pixels>,
 6968        content_origin: gpui::Point<Pixels>,
 6969        visible_row_range: Range<DisplayRow>,
 6970        line_layouts: &[LineWithInvisibles],
 6971        line_height: Pixels,
 6972        scroll_pixel_position: gpui::Point<Pixels>,
 6973        newest_selection_head: Option<DisplayPoint>,
 6974        target_display_point: DisplayPoint,
 6975        window: &mut Window,
 6976        cx: &mut App,
 6977    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6978        let scrolled_content_origin =
 6979            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 6980
 6981        const SCROLL_PADDING_Y: Pixels = px(12.);
 6982
 6983        if target_display_point.row() < visible_row_range.start {
 6984            return self.render_edit_prediction_scroll_popover(
 6985                |_| SCROLL_PADDING_Y,
 6986                IconName::ArrowUp,
 6987                visible_row_range,
 6988                line_layouts,
 6989                newest_selection_head,
 6990                scrolled_content_origin,
 6991                window,
 6992                cx,
 6993            );
 6994        } else if target_display_point.row() >= visible_row_range.end {
 6995            return self.render_edit_prediction_scroll_popover(
 6996                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 6997                IconName::ArrowDown,
 6998                visible_row_range,
 6999                line_layouts,
 7000                newest_selection_head,
 7001                scrolled_content_origin,
 7002                window,
 7003                cx,
 7004            );
 7005        }
 7006
 7007        const POLE_WIDTH: Pixels = px(2.);
 7008
 7009        let line_layout =
 7010            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7011        let target_column = target_display_point.column() as usize;
 7012
 7013        let target_x = line_layout.x_for_index(target_column);
 7014        let target_y =
 7015            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7016
 7017        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7018
 7019        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7020        border_color.l += 0.001;
 7021
 7022        let mut element = v_flex()
 7023            .items_end()
 7024            .when(flag_on_right, |el| el.items_start())
 7025            .child(if flag_on_right {
 7026                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7027                    .rounded_bl(px(0.))
 7028                    .rounded_tl(px(0.))
 7029                    .border_l_2()
 7030                    .border_color(border_color)
 7031            } else {
 7032                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7033                    .rounded_br(px(0.))
 7034                    .rounded_tr(px(0.))
 7035                    .border_r_2()
 7036                    .border_color(border_color)
 7037            })
 7038            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7039            .into_any();
 7040
 7041        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7042
 7043        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7044            - point(
 7045                if flag_on_right {
 7046                    POLE_WIDTH
 7047                } else {
 7048                    size.width - POLE_WIDTH
 7049                },
 7050                size.height - line_height,
 7051            );
 7052
 7053        origin.x = origin.x.max(content_origin.x);
 7054
 7055        element.prepaint_at(origin, window, cx);
 7056
 7057        Some((element, origin))
 7058    }
 7059
 7060    fn render_edit_prediction_scroll_popover(
 7061        &mut self,
 7062        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7063        scroll_icon: IconName,
 7064        visible_row_range: Range<DisplayRow>,
 7065        line_layouts: &[LineWithInvisibles],
 7066        newest_selection_head: Option<DisplayPoint>,
 7067        scrolled_content_origin: gpui::Point<Pixels>,
 7068        window: &mut Window,
 7069        cx: &mut App,
 7070    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7071        let mut element = self
 7072            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7073            .into_any();
 7074
 7075        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7076
 7077        let cursor = newest_selection_head?;
 7078        let cursor_row_layout =
 7079            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7080        let cursor_column = cursor.column() as usize;
 7081
 7082        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7083
 7084        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7085
 7086        element.prepaint_at(origin, window, cx);
 7087        Some((element, origin))
 7088    }
 7089
 7090    fn render_edit_prediction_eager_jump_popover(
 7091        &mut self,
 7092        text_bounds: &Bounds<Pixels>,
 7093        content_origin: gpui::Point<Pixels>,
 7094        editor_snapshot: &EditorSnapshot,
 7095        visible_row_range: Range<DisplayRow>,
 7096        scroll_top: f32,
 7097        scroll_bottom: f32,
 7098        line_height: Pixels,
 7099        scroll_pixel_position: gpui::Point<Pixels>,
 7100        target_display_point: DisplayPoint,
 7101        editor_width: Pixels,
 7102        window: &mut Window,
 7103        cx: &mut App,
 7104    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7105        if target_display_point.row().as_f32() < scroll_top {
 7106            let mut element = self
 7107                .render_edit_prediction_line_popover(
 7108                    "Jump to Edit",
 7109                    Some(IconName::ArrowUp),
 7110                    window,
 7111                    cx,
 7112                )?
 7113                .into_any();
 7114
 7115            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7116            let offset = point(
 7117                (text_bounds.size.width - size.width) / 2.,
 7118                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7119            );
 7120
 7121            let origin = text_bounds.origin + offset;
 7122            element.prepaint_at(origin, window, cx);
 7123            Some((element, origin))
 7124        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7125            let mut element = self
 7126                .render_edit_prediction_line_popover(
 7127                    "Jump to Edit",
 7128                    Some(IconName::ArrowDown),
 7129                    window,
 7130                    cx,
 7131                )?
 7132                .into_any();
 7133
 7134            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7135            let offset = point(
 7136                (text_bounds.size.width - size.width) / 2.,
 7137                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7138            );
 7139
 7140            let origin = text_bounds.origin + offset;
 7141            element.prepaint_at(origin, window, cx);
 7142            Some((element, origin))
 7143        } else {
 7144            self.render_edit_prediction_end_of_line_popover(
 7145                "Jump to Edit",
 7146                editor_snapshot,
 7147                visible_row_range,
 7148                target_display_point,
 7149                line_height,
 7150                scroll_pixel_position,
 7151                content_origin,
 7152                editor_width,
 7153                window,
 7154                cx,
 7155            )
 7156        }
 7157    }
 7158
 7159    fn render_edit_prediction_end_of_line_popover(
 7160        self: &mut Editor,
 7161        label: &'static str,
 7162        editor_snapshot: &EditorSnapshot,
 7163        visible_row_range: Range<DisplayRow>,
 7164        target_display_point: DisplayPoint,
 7165        line_height: Pixels,
 7166        scroll_pixel_position: gpui::Point<Pixels>,
 7167        content_origin: gpui::Point<Pixels>,
 7168        editor_width: Pixels,
 7169        window: &mut Window,
 7170        cx: &mut App,
 7171    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7172        let target_line_end = DisplayPoint::new(
 7173            target_display_point.row(),
 7174            editor_snapshot.line_len(target_display_point.row()),
 7175        );
 7176
 7177        let mut element = self
 7178            .render_edit_prediction_line_popover(label, None, window, cx)?
 7179            .into_any();
 7180
 7181        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7182
 7183        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7184
 7185        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7186        let mut origin = start_point
 7187            + line_origin
 7188            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7189        origin.x = origin.x.max(content_origin.x);
 7190
 7191        let max_x = content_origin.x + editor_width - size.width;
 7192
 7193        if origin.x > max_x {
 7194            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7195
 7196            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7197                origin.y += offset;
 7198                IconName::ArrowUp
 7199            } else {
 7200                origin.y -= offset;
 7201                IconName::ArrowDown
 7202            };
 7203
 7204            element = self
 7205                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7206                .into_any();
 7207
 7208            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7209
 7210            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7211        }
 7212
 7213        element.prepaint_at(origin, window, cx);
 7214        Some((element, origin))
 7215    }
 7216
 7217    fn render_edit_prediction_diff_popover(
 7218        self: &Editor,
 7219        text_bounds: &Bounds<Pixels>,
 7220        content_origin: gpui::Point<Pixels>,
 7221        editor_snapshot: &EditorSnapshot,
 7222        visible_row_range: Range<DisplayRow>,
 7223        line_layouts: &[LineWithInvisibles],
 7224        line_height: Pixels,
 7225        scroll_pixel_position: gpui::Point<Pixels>,
 7226        newest_selection_head: Option<DisplayPoint>,
 7227        editor_width: Pixels,
 7228        style: &EditorStyle,
 7229        edits: &Vec<(Range<Anchor>, String)>,
 7230        edit_preview: &Option<language::EditPreview>,
 7231        snapshot: &language::BufferSnapshot,
 7232        window: &mut Window,
 7233        cx: &mut App,
 7234    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7235        let edit_start = edits
 7236            .first()
 7237            .unwrap()
 7238            .0
 7239            .start
 7240            .to_display_point(editor_snapshot);
 7241        let edit_end = edits
 7242            .last()
 7243            .unwrap()
 7244            .0
 7245            .end
 7246            .to_display_point(editor_snapshot);
 7247
 7248        let is_visible = visible_row_range.contains(&edit_start.row())
 7249            || visible_row_range.contains(&edit_end.row());
 7250        if !is_visible {
 7251            return None;
 7252        }
 7253
 7254        let highlighted_edits =
 7255            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7256
 7257        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7258        let line_count = highlighted_edits.text.lines().count();
 7259
 7260        const BORDER_WIDTH: Pixels = px(1.);
 7261
 7262        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7263        let has_keybind = keybind.is_some();
 7264
 7265        let mut element = h_flex()
 7266            .items_start()
 7267            .child(
 7268                h_flex()
 7269                    .bg(cx.theme().colors().editor_background)
 7270                    .border(BORDER_WIDTH)
 7271                    .shadow_sm()
 7272                    .border_color(cx.theme().colors().border)
 7273                    .rounded_l_lg()
 7274                    .when(line_count > 1, |el| el.rounded_br_lg())
 7275                    .pr_1()
 7276                    .child(styled_text),
 7277            )
 7278            .child(
 7279                h_flex()
 7280                    .h(line_height + BORDER_WIDTH * 2.)
 7281                    .px_1p5()
 7282                    .gap_1()
 7283                    // Workaround: For some reason, there's a gap if we don't do this
 7284                    .ml(-BORDER_WIDTH)
 7285                    .shadow(smallvec![gpui::BoxShadow {
 7286                        color: gpui::black().opacity(0.05),
 7287                        offset: point(px(1.), px(1.)),
 7288                        blur_radius: px(2.),
 7289                        spread_radius: px(0.),
 7290                    }])
 7291                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7292                    .border(BORDER_WIDTH)
 7293                    .border_color(cx.theme().colors().border)
 7294                    .rounded_r_lg()
 7295                    .id("edit_prediction_diff_popover_keybind")
 7296                    .when(!has_keybind, |el| {
 7297                        let status_colors = cx.theme().status();
 7298
 7299                        el.bg(status_colors.error_background)
 7300                            .border_color(status_colors.error.opacity(0.6))
 7301                            .child(Icon::new(IconName::Info).color(Color::Error))
 7302                            .cursor_default()
 7303                            .hoverable_tooltip(move |_window, cx| {
 7304                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7305                            })
 7306                    })
 7307                    .children(keybind),
 7308            )
 7309            .into_any();
 7310
 7311        let longest_row =
 7312            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7313        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7314            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7315        } else {
 7316            layout_line(
 7317                longest_row,
 7318                editor_snapshot,
 7319                style,
 7320                editor_width,
 7321                |_| false,
 7322                window,
 7323                cx,
 7324            )
 7325            .width
 7326        };
 7327
 7328        let viewport_bounds =
 7329            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7330                right: -EditorElement::SCROLLBAR_WIDTH,
 7331                ..Default::default()
 7332            });
 7333
 7334        let x_after_longest =
 7335            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7336                - scroll_pixel_position.x;
 7337
 7338        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7339
 7340        // Fully visible if it can be displayed within the window (allow overlapping other
 7341        // panes). However, this is only allowed if the popover starts within text_bounds.
 7342        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7343            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7344
 7345        let mut origin = if can_position_to_the_right {
 7346            point(
 7347                x_after_longest,
 7348                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 7349                    - scroll_pixel_position.y,
 7350            )
 7351        } else {
 7352            let cursor_row = newest_selection_head.map(|head| head.row());
 7353            let above_edit = edit_start
 7354                .row()
 7355                .0
 7356                .checked_sub(line_count as u32)
 7357                .map(DisplayRow);
 7358            let below_edit = Some(edit_end.row() + 1);
 7359            let above_cursor =
 7360                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 7361            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 7362
 7363            // Place the edit popover adjacent to the edit if there is a location
 7364            // available that is onscreen and does not obscure the cursor. Otherwise,
 7365            // place it adjacent to the cursor.
 7366            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 7367                .into_iter()
 7368                .flatten()
 7369                .find(|&start_row| {
 7370                    let end_row = start_row + line_count as u32;
 7371                    visible_row_range.contains(&start_row)
 7372                        && visible_row_range.contains(&end_row)
 7373                        && cursor_row.map_or(true, |cursor_row| {
 7374                            !((start_row..end_row).contains(&cursor_row))
 7375                        })
 7376                })?;
 7377
 7378            content_origin
 7379                + point(
 7380                    -scroll_pixel_position.x,
 7381                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 7382                )
 7383        };
 7384
 7385        origin.x -= BORDER_WIDTH;
 7386
 7387        window.defer_draw(element, origin, 1);
 7388
 7389        // Do not return an element, since it will already be drawn due to defer_draw.
 7390        None
 7391    }
 7392
 7393    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 7394        px(30.)
 7395    }
 7396
 7397    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 7398        if self.read_only(cx) {
 7399            cx.theme().players().read_only()
 7400        } else {
 7401            self.style.as_ref().unwrap().local_player
 7402        }
 7403    }
 7404
 7405    fn render_edit_prediction_accept_keybind(
 7406        &self,
 7407        window: &mut Window,
 7408        cx: &App,
 7409    ) -> Option<AnyElement> {
 7410        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 7411        let accept_keystroke = accept_binding.keystroke()?;
 7412
 7413        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7414
 7415        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 7416            Color::Accent
 7417        } else {
 7418            Color::Muted
 7419        };
 7420
 7421        h_flex()
 7422            .px_0p5()
 7423            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 7424            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7425            .text_size(TextSize::XSmall.rems(cx))
 7426            .child(h_flex().children(ui::render_modifiers(
 7427                &accept_keystroke.modifiers,
 7428                PlatformStyle::platform(),
 7429                Some(modifiers_color),
 7430                Some(IconSize::XSmall.rems().into()),
 7431                true,
 7432            )))
 7433            .when(is_platform_style_mac, |parent| {
 7434                parent.child(accept_keystroke.key.clone())
 7435            })
 7436            .when(!is_platform_style_mac, |parent| {
 7437                parent.child(
 7438                    Key::new(
 7439                        util::capitalize(&accept_keystroke.key),
 7440                        Some(Color::Default),
 7441                    )
 7442                    .size(Some(IconSize::XSmall.rems().into())),
 7443                )
 7444            })
 7445            .into_any()
 7446            .into()
 7447    }
 7448
 7449    fn render_edit_prediction_line_popover(
 7450        &self,
 7451        label: impl Into<SharedString>,
 7452        icon: Option<IconName>,
 7453        window: &mut Window,
 7454        cx: &App,
 7455    ) -> Option<Stateful<Div>> {
 7456        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 7457
 7458        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7459        let has_keybind = keybind.is_some();
 7460
 7461        let result = h_flex()
 7462            .id("ep-line-popover")
 7463            .py_0p5()
 7464            .pl_1()
 7465            .pr(padding_right)
 7466            .gap_1()
 7467            .rounded_md()
 7468            .border_1()
 7469            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7470            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 7471            .shadow_sm()
 7472            .when(!has_keybind, |el| {
 7473                let status_colors = cx.theme().status();
 7474
 7475                el.bg(status_colors.error_background)
 7476                    .border_color(status_colors.error.opacity(0.6))
 7477                    .pl_2()
 7478                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 7479                    .cursor_default()
 7480                    .hoverable_tooltip(move |_window, cx| {
 7481                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7482                    })
 7483            })
 7484            .children(keybind)
 7485            .child(
 7486                Label::new(label)
 7487                    .size(LabelSize::Small)
 7488                    .when(!has_keybind, |el| {
 7489                        el.color(cx.theme().status().error.into()).strikethrough()
 7490                    }),
 7491            )
 7492            .when(!has_keybind, |el| {
 7493                el.child(
 7494                    h_flex().ml_1().child(
 7495                        Icon::new(IconName::Info)
 7496                            .size(IconSize::Small)
 7497                            .color(cx.theme().status().error.into()),
 7498                    ),
 7499                )
 7500            })
 7501            .when_some(icon, |element, icon| {
 7502                element.child(
 7503                    div()
 7504                        .mt(px(1.5))
 7505                        .child(Icon::new(icon).size(IconSize::Small)),
 7506                )
 7507            });
 7508
 7509        Some(result)
 7510    }
 7511
 7512    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 7513        let accent_color = cx.theme().colors().text_accent;
 7514        let editor_bg_color = cx.theme().colors().editor_background;
 7515        editor_bg_color.blend(accent_color.opacity(0.1))
 7516    }
 7517
 7518    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 7519        let accent_color = cx.theme().colors().text_accent;
 7520        let editor_bg_color = cx.theme().colors().editor_background;
 7521        editor_bg_color.blend(accent_color.opacity(0.6))
 7522    }
 7523
 7524    fn render_edit_prediction_cursor_popover(
 7525        &self,
 7526        min_width: Pixels,
 7527        max_width: Pixels,
 7528        cursor_point: Point,
 7529        style: &EditorStyle,
 7530        accept_keystroke: Option<&gpui::Keystroke>,
 7531        _window: &Window,
 7532        cx: &mut Context<Editor>,
 7533    ) -> Option<AnyElement> {
 7534        let provider = self.edit_prediction_provider.as_ref()?;
 7535
 7536        if provider.provider.needs_terms_acceptance(cx) {
 7537            return Some(
 7538                h_flex()
 7539                    .min_w(min_width)
 7540                    .flex_1()
 7541                    .px_2()
 7542                    .py_1()
 7543                    .gap_3()
 7544                    .elevation_2(cx)
 7545                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 7546                    .id("accept-terms")
 7547                    .cursor_pointer()
 7548                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 7549                    .on_click(cx.listener(|this, _event, window, cx| {
 7550                        cx.stop_propagation();
 7551                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 7552                        window.dispatch_action(
 7553                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 7554                            cx,
 7555                        );
 7556                    }))
 7557                    .child(
 7558                        h_flex()
 7559                            .flex_1()
 7560                            .gap_2()
 7561                            .child(Icon::new(IconName::ZedPredict))
 7562                            .child(Label::new("Accept Terms of Service"))
 7563                            .child(div().w_full())
 7564                            .child(
 7565                                Icon::new(IconName::ArrowUpRight)
 7566                                    .color(Color::Muted)
 7567                                    .size(IconSize::Small),
 7568                            )
 7569                            .into_any_element(),
 7570                    )
 7571                    .into_any(),
 7572            );
 7573        }
 7574
 7575        let is_refreshing = provider.provider.is_refreshing(cx);
 7576
 7577        fn pending_completion_container() -> Div {
 7578            h_flex()
 7579                .h_full()
 7580                .flex_1()
 7581                .gap_2()
 7582                .child(Icon::new(IconName::ZedPredict))
 7583        }
 7584
 7585        let completion = match &self.active_inline_completion {
 7586            Some(prediction) => {
 7587                if !self.has_visible_completions_menu() {
 7588                    const RADIUS: Pixels = px(6.);
 7589                    const BORDER_WIDTH: Pixels = px(1.);
 7590
 7591                    return Some(
 7592                        h_flex()
 7593                            .elevation_2(cx)
 7594                            .border(BORDER_WIDTH)
 7595                            .border_color(cx.theme().colors().border)
 7596                            .when(accept_keystroke.is_none(), |el| {
 7597                                el.border_color(cx.theme().status().error)
 7598                            })
 7599                            .rounded(RADIUS)
 7600                            .rounded_tl(px(0.))
 7601                            .overflow_hidden()
 7602                            .child(div().px_1p5().child(match &prediction.completion {
 7603                                InlineCompletion::Move { target, snapshot } => {
 7604                                    use text::ToPoint as _;
 7605                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 7606                                    {
 7607                                        Icon::new(IconName::ZedPredictDown)
 7608                                    } else {
 7609                                        Icon::new(IconName::ZedPredictUp)
 7610                                    }
 7611                                }
 7612                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 7613                            }))
 7614                            .child(
 7615                                h_flex()
 7616                                    .gap_1()
 7617                                    .py_1()
 7618                                    .px_2()
 7619                                    .rounded_r(RADIUS - BORDER_WIDTH)
 7620                                    .border_l_1()
 7621                                    .border_color(cx.theme().colors().border)
 7622                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7623                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 7624                                        el.child(
 7625                                            Label::new("Hold")
 7626                                                .size(LabelSize::Small)
 7627                                                .when(accept_keystroke.is_none(), |el| {
 7628                                                    el.strikethrough()
 7629                                                })
 7630                                                .line_height_style(LineHeightStyle::UiLabel),
 7631                                        )
 7632                                    })
 7633                                    .id("edit_prediction_cursor_popover_keybind")
 7634                                    .when(accept_keystroke.is_none(), |el| {
 7635                                        let status_colors = cx.theme().status();
 7636
 7637                                        el.bg(status_colors.error_background)
 7638                                            .border_color(status_colors.error.opacity(0.6))
 7639                                            .child(Icon::new(IconName::Info).color(Color::Error))
 7640                                            .cursor_default()
 7641                                            .hoverable_tooltip(move |_window, cx| {
 7642                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 7643                                                    .into()
 7644                                            })
 7645                                    })
 7646                                    .when_some(
 7647                                        accept_keystroke.as_ref(),
 7648                                        |el, accept_keystroke| {
 7649                                            el.child(h_flex().children(ui::render_modifiers(
 7650                                                &accept_keystroke.modifiers,
 7651                                                PlatformStyle::platform(),
 7652                                                Some(Color::Default),
 7653                                                Some(IconSize::XSmall.rems().into()),
 7654                                                false,
 7655                                            )))
 7656                                        },
 7657                                    ),
 7658                            )
 7659                            .into_any(),
 7660                    );
 7661                }
 7662
 7663                self.render_edit_prediction_cursor_popover_preview(
 7664                    prediction,
 7665                    cursor_point,
 7666                    style,
 7667                    cx,
 7668                )?
 7669            }
 7670
 7671            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 7672                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 7673                    stale_completion,
 7674                    cursor_point,
 7675                    style,
 7676                    cx,
 7677                )?,
 7678
 7679                None => {
 7680                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 7681                }
 7682            },
 7683
 7684            None => pending_completion_container().child(Label::new("No Prediction")),
 7685        };
 7686
 7687        let completion = if is_refreshing {
 7688            completion
 7689                .with_animation(
 7690                    "loading-completion",
 7691                    Animation::new(Duration::from_secs(2))
 7692                        .repeat()
 7693                        .with_easing(pulsating_between(0.4, 0.8)),
 7694                    |label, delta| label.opacity(delta),
 7695                )
 7696                .into_any_element()
 7697        } else {
 7698            completion.into_any_element()
 7699        };
 7700
 7701        let has_completion = self.active_inline_completion.is_some();
 7702
 7703        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7704        Some(
 7705            h_flex()
 7706                .min_w(min_width)
 7707                .max_w(max_width)
 7708                .flex_1()
 7709                .elevation_2(cx)
 7710                .border_color(cx.theme().colors().border)
 7711                .child(
 7712                    div()
 7713                        .flex_1()
 7714                        .py_1()
 7715                        .px_2()
 7716                        .overflow_hidden()
 7717                        .child(completion),
 7718                )
 7719                .when_some(accept_keystroke, |el, accept_keystroke| {
 7720                    if !accept_keystroke.modifiers.modified() {
 7721                        return el;
 7722                    }
 7723
 7724                    el.child(
 7725                        h_flex()
 7726                            .h_full()
 7727                            .border_l_1()
 7728                            .rounded_r_lg()
 7729                            .border_color(cx.theme().colors().border)
 7730                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7731                            .gap_1()
 7732                            .py_1()
 7733                            .px_2()
 7734                            .child(
 7735                                h_flex()
 7736                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7737                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 7738                                    .child(h_flex().children(ui::render_modifiers(
 7739                                        &accept_keystroke.modifiers,
 7740                                        PlatformStyle::platform(),
 7741                                        Some(if !has_completion {
 7742                                            Color::Muted
 7743                                        } else {
 7744                                            Color::Default
 7745                                        }),
 7746                                        None,
 7747                                        false,
 7748                                    ))),
 7749                            )
 7750                            .child(Label::new("Preview").into_any_element())
 7751                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 7752                    )
 7753                })
 7754                .into_any(),
 7755        )
 7756    }
 7757
 7758    fn render_edit_prediction_cursor_popover_preview(
 7759        &self,
 7760        completion: &InlineCompletionState,
 7761        cursor_point: Point,
 7762        style: &EditorStyle,
 7763        cx: &mut Context<Editor>,
 7764    ) -> Option<Div> {
 7765        use text::ToPoint as _;
 7766
 7767        fn render_relative_row_jump(
 7768            prefix: impl Into<String>,
 7769            current_row: u32,
 7770            target_row: u32,
 7771        ) -> Div {
 7772            let (row_diff, arrow) = if target_row < current_row {
 7773                (current_row - target_row, IconName::ArrowUp)
 7774            } else {
 7775                (target_row - current_row, IconName::ArrowDown)
 7776            };
 7777
 7778            h_flex()
 7779                .child(
 7780                    Label::new(format!("{}{}", prefix.into(), row_diff))
 7781                        .color(Color::Muted)
 7782                        .size(LabelSize::Small),
 7783                )
 7784                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 7785        }
 7786
 7787        match &completion.completion {
 7788            InlineCompletion::Move {
 7789                target, snapshot, ..
 7790            } => Some(
 7791                h_flex()
 7792                    .px_2()
 7793                    .gap_2()
 7794                    .flex_1()
 7795                    .child(
 7796                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 7797                            Icon::new(IconName::ZedPredictDown)
 7798                        } else {
 7799                            Icon::new(IconName::ZedPredictUp)
 7800                        },
 7801                    )
 7802                    .child(Label::new("Jump to Edit")),
 7803            ),
 7804
 7805            InlineCompletion::Edit {
 7806                edits,
 7807                edit_preview,
 7808                snapshot,
 7809                display_mode: _,
 7810            } => {
 7811                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 7812
 7813                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 7814                    &snapshot,
 7815                    &edits,
 7816                    edit_preview.as_ref()?,
 7817                    true,
 7818                    cx,
 7819                )
 7820                .first_line_preview();
 7821
 7822                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 7823                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 7824
 7825                let preview = h_flex()
 7826                    .gap_1()
 7827                    .min_w_16()
 7828                    .child(styled_text)
 7829                    .when(has_more_lines, |parent| parent.child(""));
 7830
 7831                let left = if first_edit_row != cursor_point.row {
 7832                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 7833                        .into_any_element()
 7834                } else {
 7835                    Icon::new(IconName::ZedPredict).into_any_element()
 7836                };
 7837
 7838                Some(
 7839                    h_flex()
 7840                        .h_full()
 7841                        .flex_1()
 7842                        .gap_2()
 7843                        .pr_1()
 7844                        .overflow_x_hidden()
 7845                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7846                        .child(left)
 7847                        .child(preview),
 7848                )
 7849            }
 7850        }
 7851    }
 7852
 7853    fn render_context_menu(
 7854        &self,
 7855        style: &EditorStyle,
 7856        max_height_in_lines: u32,
 7857        window: &mut Window,
 7858        cx: &mut Context<Editor>,
 7859    ) -> Option<AnyElement> {
 7860        let menu = self.context_menu.borrow();
 7861        let menu = menu.as_ref()?;
 7862        if !menu.visible() {
 7863            return None;
 7864        };
 7865        Some(menu.render(style, max_height_in_lines, window, cx))
 7866    }
 7867
 7868    fn render_context_menu_aside(
 7869        &mut self,
 7870        max_size: Size<Pixels>,
 7871        window: &mut Window,
 7872        cx: &mut Context<Editor>,
 7873    ) -> Option<AnyElement> {
 7874        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 7875            if menu.visible() {
 7876                menu.render_aside(self, max_size, window, cx)
 7877            } else {
 7878                None
 7879            }
 7880        })
 7881    }
 7882
 7883    fn hide_context_menu(
 7884        &mut self,
 7885        window: &mut Window,
 7886        cx: &mut Context<Self>,
 7887    ) -> Option<CodeContextMenu> {
 7888        cx.notify();
 7889        self.completion_tasks.clear();
 7890        let context_menu = self.context_menu.borrow_mut().take();
 7891        self.stale_inline_completion_in_menu.take();
 7892        self.update_visible_inline_completion(window, cx);
 7893        context_menu
 7894    }
 7895
 7896    fn show_snippet_choices(
 7897        &mut self,
 7898        choices: &Vec<String>,
 7899        selection: Range<Anchor>,
 7900        cx: &mut Context<Self>,
 7901    ) {
 7902        if selection.start.buffer_id.is_none() {
 7903            return;
 7904        }
 7905        let buffer_id = selection.start.buffer_id.unwrap();
 7906        let buffer = self.buffer().read(cx).buffer(buffer_id);
 7907        let id = post_inc(&mut self.next_completion_id);
 7908
 7909        if let Some(buffer) = buffer {
 7910            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 7911                CompletionsMenu::new_snippet_choices(id, true, choices, selection, buffer),
 7912            ));
 7913        }
 7914    }
 7915
 7916    pub fn insert_snippet(
 7917        &mut self,
 7918        insertion_ranges: &[Range<usize>],
 7919        snippet: Snippet,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) -> Result<()> {
 7923        struct Tabstop<T> {
 7924            is_end_tabstop: bool,
 7925            ranges: Vec<Range<T>>,
 7926            choices: Option<Vec<String>>,
 7927        }
 7928
 7929        let tabstops = self.buffer.update(cx, |buffer, cx| {
 7930            let snippet_text: Arc<str> = snippet.text.clone().into();
 7931            let edits = insertion_ranges
 7932                .iter()
 7933                .cloned()
 7934                .map(|range| (range, snippet_text.clone()));
 7935            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 7936
 7937            let snapshot = &*buffer.read(cx);
 7938            let snippet = &snippet;
 7939            snippet
 7940                .tabstops
 7941                .iter()
 7942                .map(|tabstop| {
 7943                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 7944                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 7945                    });
 7946                    let mut tabstop_ranges = tabstop
 7947                        .ranges
 7948                        .iter()
 7949                        .flat_map(|tabstop_range| {
 7950                            let mut delta = 0_isize;
 7951                            insertion_ranges.iter().map(move |insertion_range| {
 7952                                let insertion_start = insertion_range.start as isize + delta;
 7953                                delta +=
 7954                                    snippet.text.len() as isize - insertion_range.len() as isize;
 7955
 7956                                let start = ((insertion_start + tabstop_range.start) as usize)
 7957                                    .min(snapshot.len());
 7958                                let end = ((insertion_start + tabstop_range.end) as usize)
 7959                                    .min(snapshot.len());
 7960                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 7961                            })
 7962                        })
 7963                        .collect::<Vec<_>>();
 7964                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 7965
 7966                    Tabstop {
 7967                        is_end_tabstop,
 7968                        ranges: tabstop_ranges,
 7969                        choices: tabstop.choices.clone(),
 7970                    }
 7971                })
 7972                .collect::<Vec<_>>()
 7973        });
 7974        if let Some(tabstop) = tabstops.first() {
 7975            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7976                s.select_ranges(tabstop.ranges.iter().cloned());
 7977            });
 7978
 7979            if let Some(choices) = &tabstop.choices {
 7980                if let Some(selection) = tabstop.ranges.first() {
 7981                    self.show_snippet_choices(choices, selection.clone(), cx)
 7982                }
 7983            }
 7984
 7985            // If we're already at the last tabstop and it's at the end of the snippet,
 7986            // we're done, we don't need to keep the state around.
 7987            if !tabstop.is_end_tabstop {
 7988                let choices = tabstops
 7989                    .iter()
 7990                    .map(|tabstop| tabstop.choices.clone())
 7991                    .collect();
 7992
 7993                let ranges = tabstops
 7994                    .into_iter()
 7995                    .map(|tabstop| tabstop.ranges)
 7996                    .collect::<Vec<_>>();
 7997
 7998                self.snippet_stack.push(SnippetState {
 7999                    active_index: 0,
 8000                    ranges,
 8001                    choices,
 8002                });
 8003            }
 8004
 8005            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8006            if self.autoclose_regions.is_empty() {
 8007                let snapshot = self.buffer.read(cx).snapshot(cx);
 8008                for selection in &mut self.selections.all::<Point>(cx) {
 8009                    let selection_head = selection.head();
 8010                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8011                        continue;
 8012                    };
 8013
 8014                    let mut bracket_pair = None;
 8015                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8016                    let prev_chars = snapshot
 8017                        .reversed_chars_at(selection_head)
 8018                        .collect::<String>();
 8019                    for (pair, enabled) in scope.brackets() {
 8020                        if enabled
 8021                            && pair.close
 8022                            && prev_chars.starts_with(pair.start.as_str())
 8023                            && next_chars.starts_with(pair.end.as_str())
 8024                        {
 8025                            bracket_pair = Some(pair.clone());
 8026                            break;
 8027                        }
 8028                    }
 8029                    if let Some(pair) = bracket_pair {
 8030                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8031                        let autoclose_enabled =
 8032                            self.use_autoclose && snapshot_settings.use_autoclose;
 8033                        if autoclose_enabled {
 8034                            let start = snapshot.anchor_after(selection_head);
 8035                            let end = snapshot.anchor_after(selection_head);
 8036                            self.autoclose_regions.push(AutocloseRegion {
 8037                                selection_id: selection.id,
 8038                                range: start..end,
 8039                                pair,
 8040                            });
 8041                        }
 8042                    }
 8043                }
 8044            }
 8045        }
 8046        Ok(())
 8047    }
 8048
 8049    pub fn move_to_next_snippet_tabstop(
 8050        &mut self,
 8051        window: &mut Window,
 8052        cx: &mut Context<Self>,
 8053    ) -> bool {
 8054        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8055    }
 8056
 8057    pub fn move_to_prev_snippet_tabstop(
 8058        &mut self,
 8059        window: &mut Window,
 8060        cx: &mut Context<Self>,
 8061    ) -> bool {
 8062        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8063    }
 8064
 8065    pub fn move_to_snippet_tabstop(
 8066        &mut self,
 8067        bias: Bias,
 8068        window: &mut Window,
 8069        cx: &mut Context<Self>,
 8070    ) -> bool {
 8071        if let Some(mut snippet) = self.snippet_stack.pop() {
 8072            match bias {
 8073                Bias::Left => {
 8074                    if snippet.active_index > 0 {
 8075                        snippet.active_index -= 1;
 8076                    } else {
 8077                        self.snippet_stack.push(snippet);
 8078                        return false;
 8079                    }
 8080                }
 8081                Bias::Right => {
 8082                    if snippet.active_index + 1 < snippet.ranges.len() {
 8083                        snippet.active_index += 1;
 8084                    } else {
 8085                        self.snippet_stack.push(snippet);
 8086                        return false;
 8087                    }
 8088                }
 8089            }
 8090            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8091                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8092                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8093                });
 8094
 8095                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8096                    if let Some(selection) = current_ranges.first() {
 8097                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8098                    }
 8099                }
 8100
 8101                // If snippet state is not at the last tabstop, push it back on the stack
 8102                if snippet.active_index + 1 < snippet.ranges.len() {
 8103                    self.snippet_stack.push(snippet);
 8104                }
 8105                return true;
 8106            }
 8107        }
 8108
 8109        false
 8110    }
 8111
 8112    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8113        self.transact(window, cx, |this, window, cx| {
 8114            this.select_all(&SelectAll, window, cx);
 8115            this.insert("", window, cx);
 8116        });
 8117    }
 8118
 8119    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8120        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8121        self.transact(window, cx, |this, window, cx| {
 8122            this.select_autoclose_pair(window, cx);
 8123            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8124            if !this.linked_edit_ranges.is_empty() {
 8125                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8126                let snapshot = this.buffer.read(cx).snapshot(cx);
 8127
 8128                for selection in selections.iter() {
 8129                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8130                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8131                    if selection_start.buffer_id != selection_end.buffer_id {
 8132                        continue;
 8133                    }
 8134                    if let Some(ranges) =
 8135                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8136                    {
 8137                        for (buffer, entries) in ranges {
 8138                            linked_ranges.entry(buffer).or_default().extend(entries);
 8139                        }
 8140                    }
 8141                }
 8142            }
 8143
 8144            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8145            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8146            for selection in &mut selections {
 8147                if selection.is_empty() {
 8148                    let old_head = selection.head();
 8149                    let mut new_head =
 8150                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8151                            .to_point(&display_map);
 8152                    if let Some((buffer, line_buffer_range)) = display_map
 8153                        .buffer_snapshot
 8154                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8155                    {
 8156                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8157                        let indent_len = match indent_size.kind {
 8158                            IndentKind::Space => {
 8159                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8160                            }
 8161                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8162                        };
 8163                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8164                            let indent_len = indent_len.get();
 8165                            new_head = cmp::min(
 8166                                new_head,
 8167                                MultiBufferPoint::new(
 8168                                    old_head.row,
 8169                                    ((old_head.column - 1) / indent_len) * indent_len,
 8170                                ),
 8171                            );
 8172                        }
 8173                    }
 8174
 8175                    selection.set_head(new_head, SelectionGoal::None);
 8176                }
 8177            }
 8178
 8179            this.signature_help_state.set_backspace_pressed(true);
 8180            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8181                s.select(selections)
 8182            });
 8183            this.insert("", window, cx);
 8184            let empty_str: Arc<str> = Arc::from("");
 8185            for (buffer, edits) in linked_ranges {
 8186                let snapshot = buffer.read(cx).snapshot();
 8187                use text::ToPoint as TP;
 8188
 8189                let edits = edits
 8190                    .into_iter()
 8191                    .map(|range| {
 8192                        let end_point = TP::to_point(&range.end, &snapshot);
 8193                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8194
 8195                        if end_point == start_point {
 8196                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8197                                .saturating_sub(1);
 8198                            start_point =
 8199                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8200                        };
 8201
 8202                        (start_point..end_point, empty_str.clone())
 8203                    })
 8204                    .sorted_by_key(|(range, _)| range.start)
 8205                    .collect::<Vec<_>>();
 8206                buffer.update(cx, |this, cx| {
 8207                    this.edit(edits, None, cx);
 8208                })
 8209            }
 8210            this.refresh_inline_completion(true, false, window, cx);
 8211            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8212        });
 8213    }
 8214
 8215    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8216        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8217        self.transact(window, cx, |this, window, cx| {
 8218            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8219                s.move_with(|map, selection| {
 8220                    if selection.is_empty() {
 8221                        let cursor = movement::right(map, selection.head());
 8222                        selection.end = cursor;
 8223                        selection.reversed = true;
 8224                        selection.goal = SelectionGoal::None;
 8225                    }
 8226                })
 8227            });
 8228            this.insert("", window, cx);
 8229            this.refresh_inline_completion(true, false, window, cx);
 8230        });
 8231    }
 8232
 8233    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8234        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8235        if self.move_to_prev_snippet_tabstop(window, cx) {
 8236            return;
 8237        }
 8238        self.outdent(&Outdent, window, cx);
 8239    }
 8240
 8241    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8242        if self.move_to_next_snippet_tabstop(window, cx) {
 8243            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8244            return;
 8245        }
 8246        if self.read_only(cx) {
 8247            return;
 8248        }
 8249        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8250        let mut selections = self.selections.all_adjusted(cx);
 8251        let buffer = self.buffer.read(cx);
 8252        let snapshot = buffer.snapshot(cx);
 8253        let rows_iter = selections.iter().map(|s| s.head().row);
 8254        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8255
 8256        let mut edits = Vec::new();
 8257        let mut prev_edited_row = 0;
 8258        let mut row_delta = 0;
 8259        for selection in &mut selections {
 8260            if selection.start.row != prev_edited_row {
 8261                row_delta = 0;
 8262            }
 8263            prev_edited_row = selection.end.row;
 8264
 8265            // If the selection is non-empty, then increase the indentation of the selected lines.
 8266            if !selection.is_empty() {
 8267                row_delta =
 8268                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8269                continue;
 8270            }
 8271
 8272            // If the selection is empty and the cursor is in the leading whitespace before the
 8273            // suggested indentation, then auto-indent the line.
 8274            let cursor = selection.head();
 8275            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8276            if let Some(suggested_indent) =
 8277                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8278            {
 8279                if cursor.column < suggested_indent.len
 8280                    && cursor.column <= current_indent.len
 8281                    && current_indent.len <= suggested_indent.len
 8282                {
 8283                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8284                    selection.end = selection.start;
 8285                    if row_delta == 0 {
 8286                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8287                            cursor.row,
 8288                            current_indent,
 8289                            suggested_indent,
 8290                        ));
 8291                        row_delta = suggested_indent.len - current_indent.len;
 8292                    }
 8293                    continue;
 8294                }
 8295            }
 8296
 8297            // Otherwise, insert a hard or soft tab.
 8298            let settings = buffer.language_settings_at(cursor, cx);
 8299            let tab_size = if settings.hard_tabs {
 8300                IndentSize::tab()
 8301            } else {
 8302                let tab_size = settings.tab_size.get();
 8303                let indent_remainder = snapshot
 8304                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8305                    .flat_map(str::chars)
 8306                    .fold(row_delta % tab_size, |counter: u32, c| {
 8307                        if c == '\t' {
 8308                            0
 8309                        } else {
 8310                            (counter + 1) % tab_size
 8311                        }
 8312                    });
 8313
 8314                let chars_to_next_tab_stop = tab_size - indent_remainder;
 8315                IndentSize::spaces(chars_to_next_tab_stop)
 8316            };
 8317            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 8318            selection.end = selection.start;
 8319            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 8320            row_delta += tab_size.len;
 8321        }
 8322
 8323        self.transact(window, cx, |this, window, cx| {
 8324            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8325            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8326                s.select(selections)
 8327            });
 8328            this.refresh_inline_completion(true, false, window, cx);
 8329        });
 8330    }
 8331
 8332    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 8333        if self.read_only(cx) {
 8334            return;
 8335        }
 8336        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8337        let mut selections = self.selections.all::<Point>(cx);
 8338        let mut prev_edited_row = 0;
 8339        let mut row_delta = 0;
 8340        let mut edits = Vec::new();
 8341        let buffer = self.buffer.read(cx);
 8342        let snapshot = buffer.snapshot(cx);
 8343        for selection in &mut selections {
 8344            if selection.start.row != prev_edited_row {
 8345                row_delta = 0;
 8346            }
 8347            prev_edited_row = selection.end.row;
 8348
 8349            row_delta =
 8350                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8351        }
 8352
 8353        self.transact(window, cx, |this, window, cx| {
 8354            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8355            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8356                s.select(selections)
 8357            });
 8358        });
 8359    }
 8360
 8361    fn indent_selection(
 8362        buffer: &MultiBuffer,
 8363        snapshot: &MultiBufferSnapshot,
 8364        selection: &mut Selection<Point>,
 8365        edits: &mut Vec<(Range<Point>, String)>,
 8366        delta_for_start_row: u32,
 8367        cx: &App,
 8368    ) -> u32 {
 8369        let settings = buffer.language_settings_at(selection.start, cx);
 8370        let tab_size = settings.tab_size.get();
 8371        let indent_kind = if settings.hard_tabs {
 8372            IndentKind::Tab
 8373        } else {
 8374            IndentKind::Space
 8375        };
 8376        let mut start_row = selection.start.row;
 8377        let mut end_row = selection.end.row + 1;
 8378
 8379        // If a selection ends at the beginning of a line, don't indent
 8380        // that last line.
 8381        if selection.end.column == 0 && selection.end.row > selection.start.row {
 8382            end_row -= 1;
 8383        }
 8384
 8385        // Avoid re-indenting a row that has already been indented by a
 8386        // previous selection, but still update this selection's column
 8387        // to reflect that indentation.
 8388        if delta_for_start_row > 0 {
 8389            start_row += 1;
 8390            selection.start.column += delta_for_start_row;
 8391            if selection.end.row == selection.start.row {
 8392                selection.end.column += delta_for_start_row;
 8393            }
 8394        }
 8395
 8396        let mut delta_for_end_row = 0;
 8397        let has_multiple_rows = start_row + 1 != end_row;
 8398        for row in start_row..end_row {
 8399            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 8400            let indent_delta = match (current_indent.kind, indent_kind) {
 8401                (IndentKind::Space, IndentKind::Space) => {
 8402                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 8403                    IndentSize::spaces(columns_to_next_tab_stop)
 8404                }
 8405                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 8406                (_, IndentKind::Tab) => IndentSize::tab(),
 8407            };
 8408
 8409            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 8410                0
 8411            } else {
 8412                selection.start.column
 8413            };
 8414            let row_start = Point::new(row, start);
 8415            edits.push((
 8416                row_start..row_start,
 8417                indent_delta.chars().collect::<String>(),
 8418            ));
 8419
 8420            // Update this selection's endpoints to reflect the indentation.
 8421            if row == selection.start.row {
 8422                selection.start.column += indent_delta.len;
 8423            }
 8424            if row == selection.end.row {
 8425                selection.end.column += indent_delta.len;
 8426                delta_for_end_row = indent_delta.len;
 8427            }
 8428        }
 8429
 8430        if selection.start.row == selection.end.row {
 8431            delta_for_start_row + delta_for_end_row
 8432        } else {
 8433            delta_for_end_row
 8434        }
 8435    }
 8436
 8437    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 8438        if self.read_only(cx) {
 8439            return;
 8440        }
 8441        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8443        let selections = self.selections.all::<Point>(cx);
 8444        let mut deletion_ranges = Vec::new();
 8445        let mut last_outdent = None;
 8446        {
 8447            let buffer = self.buffer.read(cx);
 8448            let snapshot = buffer.snapshot(cx);
 8449            for selection in &selections {
 8450                let settings = buffer.language_settings_at(selection.start, cx);
 8451                let tab_size = settings.tab_size.get();
 8452                let mut rows = selection.spanned_rows(false, &display_map);
 8453
 8454                // Avoid re-outdenting a row that has already been outdented by a
 8455                // previous selection.
 8456                if let Some(last_row) = last_outdent {
 8457                    if last_row == rows.start {
 8458                        rows.start = rows.start.next_row();
 8459                    }
 8460                }
 8461                let has_multiple_rows = rows.len() > 1;
 8462                for row in rows.iter_rows() {
 8463                    let indent_size = snapshot.indent_size_for_line(row);
 8464                    if indent_size.len > 0 {
 8465                        let deletion_len = match indent_size.kind {
 8466                            IndentKind::Space => {
 8467                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 8468                                if columns_to_prev_tab_stop == 0 {
 8469                                    tab_size
 8470                                } else {
 8471                                    columns_to_prev_tab_stop
 8472                                }
 8473                            }
 8474                            IndentKind::Tab => 1,
 8475                        };
 8476                        let start = if has_multiple_rows
 8477                            || deletion_len > selection.start.column
 8478                            || indent_size.len < selection.start.column
 8479                        {
 8480                            0
 8481                        } else {
 8482                            selection.start.column - deletion_len
 8483                        };
 8484                        deletion_ranges.push(
 8485                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 8486                        );
 8487                        last_outdent = Some(row);
 8488                    }
 8489                }
 8490            }
 8491        }
 8492
 8493        self.transact(window, cx, |this, window, cx| {
 8494            this.buffer.update(cx, |buffer, cx| {
 8495                let empty_str: Arc<str> = Arc::default();
 8496                buffer.edit(
 8497                    deletion_ranges
 8498                        .into_iter()
 8499                        .map(|range| (range, empty_str.clone())),
 8500                    None,
 8501                    cx,
 8502                );
 8503            });
 8504            let selections = this.selections.all::<usize>(cx);
 8505            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8506                s.select(selections)
 8507            });
 8508        });
 8509    }
 8510
 8511    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 8512        if self.read_only(cx) {
 8513            return;
 8514        }
 8515        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8516        let selections = self
 8517            .selections
 8518            .all::<usize>(cx)
 8519            .into_iter()
 8520            .map(|s| s.range());
 8521
 8522        self.transact(window, cx, |this, window, cx| {
 8523            this.buffer.update(cx, |buffer, cx| {
 8524                buffer.autoindent_ranges(selections, cx);
 8525            });
 8526            let selections = this.selections.all::<usize>(cx);
 8527            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8528                s.select(selections)
 8529            });
 8530        });
 8531    }
 8532
 8533    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 8534        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8536        let selections = self.selections.all::<Point>(cx);
 8537
 8538        let mut new_cursors = Vec::new();
 8539        let mut edit_ranges = Vec::new();
 8540        let mut selections = selections.iter().peekable();
 8541        while let Some(selection) = selections.next() {
 8542            let mut rows = selection.spanned_rows(false, &display_map);
 8543            let goal_display_column = selection.head().to_display_point(&display_map).column();
 8544
 8545            // Accumulate contiguous regions of rows that we want to delete.
 8546            while let Some(next_selection) = selections.peek() {
 8547                let next_rows = next_selection.spanned_rows(false, &display_map);
 8548                if next_rows.start <= rows.end {
 8549                    rows.end = next_rows.end;
 8550                    selections.next().unwrap();
 8551                } else {
 8552                    break;
 8553                }
 8554            }
 8555
 8556            let buffer = &display_map.buffer_snapshot;
 8557            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 8558            let edit_end;
 8559            let cursor_buffer_row;
 8560            if buffer.max_point().row >= rows.end.0 {
 8561                // If there's a line after the range, delete the \n from the end of the row range
 8562                // and position the cursor on the next line.
 8563                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 8564                cursor_buffer_row = rows.end;
 8565            } else {
 8566                // If there isn't a line after the range, delete the \n from the line before the
 8567                // start of the row range and position the cursor there.
 8568                edit_start = edit_start.saturating_sub(1);
 8569                edit_end = buffer.len();
 8570                cursor_buffer_row = rows.start.previous_row();
 8571            }
 8572
 8573            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 8574            *cursor.column_mut() =
 8575                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 8576
 8577            new_cursors.push((
 8578                selection.id,
 8579                buffer.anchor_after(cursor.to_point(&display_map)),
 8580            ));
 8581            edit_ranges.push(edit_start..edit_end);
 8582        }
 8583
 8584        self.transact(window, cx, |this, window, cx| {
 8585            let buffer = this.buffer.update(cx, |buffer, cx| {
 8586                let empty_str: Arc<str> = Arc::default();
 8587                buffer.edit(
 8588                    edit_ranges
 8589                        .into_iter()
 8590                        .map(|range| (range, empty_str.clone())),
 8591                    None,
 8592                    cx,
 8593                );
 8594                buffer.snapshot(cx)
 8595            });
 8596            let new_selections = new_cursors
 8597                .into_iter()
 8598                .map(|(id, cursor)| {
 8599                    let cursor = cursor.to_point(&buffer);
 8600                    Selection {
 8601                        id,
 8602                        start: cursor,
 8603                        end: cursor,
 8604                        reversed: false,
 8605                        goal: SelectionGoal::None,
 8606                    }
 8607                })
 8608                .collect();
 8609
 8610            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8611                s.select(new_selections);
 8612            });
 8613        });
 8614    }
 8615
 8616    pub fn join_lines_impl(
 8617        &mut self,
 8618        insert_whitespace: bool,
 8619        window: &mut Window,
 8620        cx: &mut Context<Self>,
 8621    ) {
 8622        if self.read_only(cx) {
 8623            return;
 8624        }
 8625        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 8626        for selection in self.selections.all::<Point>(cx) {
 8627            let start = MultiBufferRow(selection.start.row);
 8628            // Treat single line selections as if they include the next line. Otherwise this action
 8629            // would do nothing for single line selections individual cursors.
 8630            let end = if selection.start.row == selection.end.row {
 8631                MultiBufferRow(selection.start.row + 1)
 8632            } else {
 8633                MultiBufferRow(selection.end.row)
 8634            };
 8635
 8636            if let Some(last_row_range) = row_ranges.last_mut() {
 8637                if start <= last_row_range.end {
 8638                    last_row_range.end = end;
 8639                    continue;
 8640                }
 8641            }
 8642            row_ranges.push(start..end);
 8643        }
 8644
 8645        let snapshot = self.buffer.read(cx).snapshot(cx);
 8646        let mut cursor_positions = Vec::new();
 8647        for row_range in &row_ranges {
 8648            let anchor = snapshot.anchor_before(Point::new(
 8649                row_range.end.previous_row().0,
 8650                snapshot.line_len(row_range.end.previous_row()),
 8651            ));
 8652            cursor_positions.push(anchor..anchor);
 8653        }
 8654
 8655        self.transact(window, cx, |this, window, cx| {
 8656            for row_range in row_ranges.into_iter().rev() {
 8657                for row in row_range.iter_rows().rev() {
 8658                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 8659                    let next_line_row = row.next_row();
 8660                    let indent = snapshot.indent_size_for_line(next_line_row);
 8661                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 8662
 8663                    let replace =
 8664                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 8665                            " "
 8666                        } else {
 8667                            ""
 8668                        };
 8669
 8670                    this.buffer.update(cx, |buffer, cx| {
 8671                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 8672                    });
 8673                }
 8674            }
 8675
 8676            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8677                s.select_anchor_ranges(cursor_positions)
 8678            });
 8679        });
 8680    }
 8681
 8682    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 8683        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8684        self.join_lines_impl(true, window, cx);
 8685    }
 8686
 8687    pub fn sort_lines_case_sensitive(
 8688        &mut self,
 8689        _: &SortLinesCaseSensitive,
 8690        window: &mut Window,
 8691        cx: &mut Context<Self>,
 8692    ) {
 8693        self.manipulate_lines(window, cx, |lines| lines.sort())
 8694    }
 8695
 8696    pub fn sort_lines_case_insensitive(
 8697        &mut self,
 8698        _: &SortLinesCaseInsensitive,
 8699        window: &mut Window,
 8700        cx: &mut Context<Self>,
 8701    ) {
 8702        self.manipulate_lines(window, cx, |lines| {
 8703            lines.sort_by_key(|line| line.to_lowercase())
 8704        })
 8705    }
 8706
 8707    pub fn unique_lines_case_insensitive(
 8708        &mut self,
 8709        _: &UniqueLinesCaseInsensitive,
 8710        window: &mut Window,
 8711        cx: &mut Context<Self>,
 8712    ) {
 8713        self.manipulate_lines(window, cx, |lines| {
 8714            let mut seen = HashSet::default();
 8715            lines.retain(|line| seen.insert(line.to_lowercase()));
 8716        })
 8717    }
 8718
 8719    pub fn unique_lines_case_sensitive(
 8720        &mut self,
 8721        _: &UniqueLinesCaseSensitive,
 8722        window: &mut Window,
 8723        cx: &mut Context<Self>,
 8724    ) {
 8725        self.manipulate_lines(window, cx, |lines| {
 8726            let mut seen = HashSet::default();
 8727            lines.retain(|line| seen.insert(*line));
 8728        })
 8729    }
 8730
 8731    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 8732        let Some(project) = self.project.clone() else {
 8733            return;
 8734        };
 8735        self.reload(project, window, cx)
 8736            .detach_and_notify_err(window, cx);
 8737    }
 8738
 8739    pub fn restore_file(
 8740        &mut self,
 8741        _: &::git::RestoreFile,
 8742        window: &mut Window,
 8743        cx: &mut Context<Self>,
 8744    ) {
 8745        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8746        let mut buffer_ids = HashSet::default();
 8747        let snapshot = self.buffer().read(cx).snapshot(cx);
 8748        for selection in self.selections.all::<usize>(cx) {
 8749            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 8750        }
 8751
 8752        let buffer = self.buffer().read(cx);
 8753        let ranges = buffer_ids
 8754            .into_iter()
 8755            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 8756            .collect::<Vec<_>>();
 8757
 8758        self.restore_hunks_in_ranges(ranges, window, cx);
 8759    }
 8760
 8761    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 8762        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8763        let selections = self
 8764            .selections
 8765            .all(cx)
 8766            .into_iter()
 8767            .map(|s| s.range())
 8768            .collect();
 8769        self.restore_hunks_in_ranges(selections, window, cx);
 8770    }
 8771
 8772    pub fn restore_hunks_in_ranges(
 8773        &mut self,
 8774        ranges: Vec<Range<Point>>,
 8775        window: &mut Window,
 8776        cx: &mut Context<Editor>,
 8777    ) {
 8778        let mut revert_changes = HashMap::default();
 8779        let chunk_by = self
 8780            .snapshot(window, cx)
 8781            .hunks_for_ranges(ranges)
 8782            .into_iter()
 8783            .chunk_by(|hunk| hunk.buffer_id);
 8784        for (buffer_id, hunks) in &chunk_by {
 8785            let hunks = hunks.collect::<Vec<_>>();
 8786            for hunk in &hunks {
 8787                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 8788            }
 8789            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 8790        }
 8791        drop(chunk_by);
 8792        if !revert_changes.is_empty() {
 8793            self.transact(window, cx, |editor, window, cx| {
 8794                editor.restore(revert_changes, window, cx);
 8795            });
 8796        }
 8797    }
 8798
 8799    pub fn open_active_item_in_terminal(
 8800        &mut self,
 8801        _: &OpenInTerminal,
 8802        window: &mut Window,
 8803        cx: &mut Context<Self>,
 8804    ) {
 8805        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 8806            let project_path = buffer.read(cx).project_path(cx)?;
 8807            let project = self.project.as_ref()?.read(cx);
 8808            let entry = project.entry_for_path(&project_path, cx)?;
 8809            let parent = match &entry.canonical_path {
 8810                Some(canonical_path) => canonical_path.to_path_buf(),
 8811                None => project.absolute_path(&project_path, cx)?,
 8812            }
 8813            .parent()?
 8814            .to_path_buf();
 8815            Some(parent)
 8816        }) {
 8817            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 8818        }
 8819    }
 8820
 8821    fn set_breakpoint_context_menu(
 8822        &mut self,
 8823        display_row: DisplayRow,
 8824        position: Option<Anchor>,
 8825        clicked_point: gpui::Point<Pixels>,
 8826        window: &mut Window,
 8827        cx: &mut Context<Self>,
 8828    ) {
 8829        if !cx.has_flag::<Debugger>() {
 8830            return;
 8831        }
 8832        let source = self
 8833            .buffer
 8834            .read(cx)
 8835            .snapshot(cx)
 8836            .anchor_before(Point::new(display_row.0, 0u32));
 8837
 8838        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 8839
 8840        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 8841            self,
 8842            source,
 8843            clicked_point,
 8844            None,
 8845            context_menu,
 8846            window,
 8847            cx,
 8848        );
 8849    }
 8850
 8851    fn add_edit_breakpoint_block(
 8852        &mut self,
 8853        anchor: Anchor,
 8854        breakpoint: &Breakpoint,
 8855        edit_action: BreakpointPromptEditAction,
 8856        window: &mut Window,
 8857        cx: &mut Context<Self>,
 8858    ) {
 8859        let weak_editor = cx.weak_entity();
 8860        let bp_prompt = cx.new(|cx| {
 8861            BreakpointPromptEditor::new(
 8862                weak_editor,
 8863                anchor,
 8864                breakpoint.clone(),
 8865                edit_action,
 8866                window,
 8867                cx,
 8868            )
 8869        });
 8870
 8871        let height = bp_prompt.update(cx, |this, cx| {
 8872            this.prompt
 8873                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 8874        });
 8875        let cloned_prompt = bp_prompt.clone();
 8876        let blocks = vec![BlockProperties {
 8877            style: BlockStyle::Sticky,
 8878            placement: BlockPlacement::Above(anchor),
 8879            height: Some(height),
 8880            render: Arc::new(move |cx| {
 8881                *cloned_prompt.read(cx).gutter_dimensions.lock() = *cx.gutter_dimensions;
 8882                cloned_prompt.clone().into_any_element()
 8883            }),
 8884            priority: 0,
 8885        }];
 8886
 8887        let focus_handle = bp_prompt.focus_handle(cx);
 8888        window.focus(&focus_handle);
 8889
 8890        let block_ids = self.insert_blocks(blocks, None, cx);
 8891        bp_prompt.update(cx, |prompt, _| {
 8892            prompt.add_block_ids(block_ids);
 8893        });
 8894    }
 8895
 8896    pub(crate) fn breakpoint_at_row(
 8897        &self,
 8898        row: u32,
 8899        window: &mut Window,
 8900        cx: &mut Context<Self>,
 8901    ) -> Option<(Anchor, Breakpoint)> {
 8902        let snapshot = self.snapshot(window, cx);
 8903        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 8904
 8905        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 8906    }
 8907
 8908    pub(crate) fn breakpoint_at_anchor(
 8909        &self,
 8910        breakpoint_position: Anchor,
 8911        snapshot: &EditorSnapshot,
 8912        cx: &mut Context<Self>,
 8913    ) -> Option<(Anchor, Breakpoint)> {
 8914        let project = self.project.clone()?;
 8915
 8916        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 8917            snapshot
 8918                .buffer_snapshot
 8919                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 8920        })?;
 8921
 8922        let enclosing_excerpt = breakpoint_position.excerpt_id;
 8923        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 8924        let buffer_snapshot = buffer.read(cx).snapshot();
 8925
 8926        let row = buffer_snapshot
 8927            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 8928            .row;
 8929
 8930        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 8931        let anchor_end = snapshot
 8932            .buffer_snapshot
 8933            .anchor_after(Point::new(row, line_len));
 8934
 8935        let bp = self
 8936            .breakpoint_store
 8937            .as_ref()?
 8938            .read_with(cx, |breakpoint_store, cx| {
 8939                breakpoint_store
 8940                    .breakpoints(
 8941                        &buffer,
 8942                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 8943                        &buffer_snapshot,
 8944                        cx,
 8945                    )
 8946                    .next()
 8947                    .and_then(|(anchor, bp)| {
 8948                        let breakpoint_row = buffer_snapshot
 8949                            .summary_for_anchor::<text::PointUtf16>(anchor)
 8950                            .row;
 8951
 8952                        if breakpoint_row == row {
 8953                            snapshot
 8954                                .buffer_snapshot
 8955                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 8956                                .map(|anchor| (anchor, bp.clone()))
 8957                        } else {
 8958                            None
 8959                        }
 8960                    })
 8961            });
 8962        bp
 8963    }
 8964
 8965    pub fn edit_log_breakpoint(
 8966        &mut self,
 8967        _: &EditLogBreakpoint,
 8968        window: &mut Window,
 8969        cx: &mut Context<Self>,
 8970    ) {
 8971        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 8972            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 8973                message: None,
 8974                state: BreakpointState::Enabled,
 8975                condition: None,
 8976                hit_condition: None,
 8977            });
 8978
 8979            self.add_edit_breakpoint_block(
 8980                anchor,
 8981                &breakpoint,
 8982                BreakpointPromptEditAction::Log,
 8983                window,
 8984                cx,
 8985            );
 8986        }
 8987    }
 8988
 8989    fn breakpoints_at_cursors(
 8990        &self,
 8991        window: &mut Window,
 8992        cx: &mut Context<Self>,
 8993    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 8994        let snapshot = self.snapshot(window, cx);
 8995        let cursors = self
 8996            .selections
 8997            .disjoint_anchors()
 8998            .into_iter()
 8999            .map(|selection| {
 9000                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9001
 9002                let breakpoint_position = self
 9003                    .breakpoint_at_row(cursor_position.row, window, cx)
 9004                    .map(|bp| bp.0)
 9005                    .unwrap_or_else(|| {
 9006                        snapshot
 9007                            .display_snapshot
 9008                            .buffer_snapshot
 9009                            .anchor_after(Point::new(cursor_position.row, 0))
 9010                    });
 9011
 9012                let breakpoint = self
 9013                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9014                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9015
 9016                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9017            })
 9018            // 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.
 9019            .collect::<HashMap<Anchor, _>>();
 9020
 9021        cursors.into_iter().collect()
 9022    }
 9023
 9024    pub fn enable_breakpoint(
 9025        &mut self,
 9026        _: &crate::actions::EnableBreakpoint,
 9027        window: &mut Window,
 9028        cx: &mut Context<Self>,
 9029    ) {
 9030        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9031            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9032                continue;
 9033            };
 9034            self.edit_breakpoint_at_anchor(
 9035                anchor,
 9036                breakpoint,
 9037                BreakpointEditAction::InvertState,
 9038                cx,
 9039            );
 9040        }
 9041    }
 9042
 9043    pub fn disable_breakpoint(
 9044        &mut self,
 9045        _: &crate::actions::DisableBreakpoint,
 9046        window: &mut Window,
 9047        cx: &mut Context<Self>,
 9048    ) {
 9049        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9050            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9051                continue;
 9052            };
 9053            self.edit_breakpoint_at_anchor(
 9054                anchor,
 9055                breakpoint,
 9056                BreakpointEditAction::InvertState,
 9057                cx,
 9058            );
 9059        }
 9060    }
 9061
 9062    pub fn toggle_breakpoint(
 9063        &mut self,
 9064        _: &crate::actions::ToggleBreakpoint,
 9065        window: &mut Window,
 9066        cx: &mut Context<Self>,
 9067    ) {
 9068        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9069            if let Some(breakpoint) = breakpoint {
 9070                self.edit_breakpoint_at_anchor(
 9071                    anchor,
 9072                    breakpoint,
 9073                    BreakpointEditAction::Toggle,
 9074                    cx,
 9075                );
 9076            } else {
 9077                self.edit_breakpoint_at_anchor(
 9078                    anchor,
 9079                    Breakpoint::new_standard(),
 9080                    BreakpointEditAction::Toggle,
 9081                    cx,
 9082                );
 9083            }
 9084        }
 9085    }
 9086
 9087    pub fn edit_breakpoint_at_anchor(
 9088        &mut self,
 9089        breakpoint_position: Anchor,
 9090        breakpoint: Breakpoint,
 9091        edit_action: BreakpointEditAction,
 9092        cx: &mut Context<Self>,
 9093    ) {
 9094        let Some(breakpoint_store) = &self.breakpoint_store else {
 9095            return;
 9096        };
 9097
 9098        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9099            if breakpoint_position == Anchor::min() {
 9100                self.buffer()
 9101                    .read(cx)
 9102                    .excerpt_buffer_ids()
 9103                    .into_iter()
 9104                    .next()
 9105            } else {
 9106                None
 9107            }
 9108        }) else {
 9109            return;
 9110        };
 9111
 9112        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9113            return;
 9114        };
 9115
 9116        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9117            breakpoint_store.toggle_breakpoint(
 9118                buffer,
 9119                (breakpoint_position.text_anchor, breakpoint),
 9120                edit_action,
 9121                cx,
 9122            );
 9123        });
 9124
 9125        cx.notify();
 9126    }
 9127
 9128    #[cfg(any(test, feature = "test-support"))]
 9129    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9130        self.breakpoint_store.clone()
 9131    }
 9132
 9133    pub fn prepare_restore_change(
 9134        &self,
 9135        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9136        hunk: &MultiBufferDiffHunk,
 9137        cx: &mut App,
 9138    ) -> Option<()> {
 9139        if hunk.is_created_file() {
 9140            return None;
 9141        }
 9142        let buffer = self.buffer.read(cx);
 9143        let diff = buffer.diff_for(hunk.buffer_id)?;
 9144        let buffer = buffer.buffer(hunk.buffer_id)?;
 9145        let buffer = buffer.read(cx);
 9146        let original_text = diff
 9147            .read(cx)
 9148            .base_text()
 9149            .as_rope()
 9150            .slice(hunk.diff_base_byte_range.clone());
 9151        let buffer_snapshot = buffer.snapshot();
 9152        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9153        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9154            probe
 9155                .0
 9156                .start
 9157                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9158                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9159        }) {
 9160            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9161            Some(())
 9162        } else {
 9163            None
 9164        }
 9165    }
 9166
 9167    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9168        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9169    }
 9170
 9171    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9172        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9173    }
 9174
 9175    fn manipulate_lines<Fn>(
 9176        &mut self,
 9177        window: &mut Window,
 9178        cx: &mut Context<Self>,
 9179        mut callback: Fn,
 9180    ) where
 9181        Fn: FnMut(&mut Vec<&str>),
 9182    {
 9183        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9184
 9185        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9186        let buffer = self.buffer.read(cx).snapshot(cx);
 9187
 9188        let mut edits = Vec::new();
 9189
 9190        let selections = self.selections.all::<Point>(cx);
 9191        let mut selections = selections.iter().peekable();
 9192        let mut contiguous_row_selections = Vec::new();
 9193        let mut new_selections = Vec::new();
 9194        let mut added_lines = 0;
 9195        let mut removed_lines = 0;
 9196
 9197        while let Some(selection) = selections.next() {
 9198            let (start_row, end_row) = consume_contiguous_rows(
 9199                &mut contiguous_row_selections,
 9200                selection,
 9201                &display_map,
 9202                &mut selections,
 9203            );
 9204
 9205            let start_point = Point::new(start_row.0, 0);
 9206            let end_point = Point::new(
 9207                end_row.previous_row().0,
 9208                buffer.line_len(end_row.previous_row()),
 9209            );
 9210            let text = buffer
 9211                .text_for_range(start_point..end_point)
 9212                .collect::<String>();
 9213
 9214            let mut lines = text.split('\n').collect_vec();
 9215
 9216            let lines_before = lines.len();
 9217            callback(&mut lines);
 9218            let lines_after = lines.len();
 9219
 9220            edits.push((start_point..end_point, lines.join("\n")));
 9221
 9222            // Selections must change based on added and removed line count
 9223            let start_row =
 9224                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9225            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9226            new_selections.push(Selection {
 9227                id: selection.id,
 9228                start: start_row,
 9229                end: end_row,
 9230                goal: SelectionGoal::None,
 9231                reversed: selection.reversed,
 9232            });
 9233
 9234            if lines_after > lines_before {
 9235                added_lines += lines_after - lines_before;
 9236            } else if lines_before > lines_after {
 9237                removed_lines += lines_before - lines_after;
 9238            }
 9239        }
 9240
 9241        self.transact(window, cx, |this, window, cx| {
 9242            let buffer = this.buffer.update(cx, |buffer, cx| {
 9243                buffer.edit(edits, None, cx);
 9244                buffer.snapshot(cx)
 9245            });
 9246
 9247            // Recalculate offsets on newly edited buffer
 9248            let new_selections = new_selections
 9249                .iter()
 9250                .map(|s| {
 9251                    let start_point = Point::new(s.start.0, 0);
 9252                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9253                    Selection {
 9254                        id: s.id,
 9255                        start: buffer.point_to_offset(start_point),
 9256                        end: buffer.point_to_offset(end_point),
 9257                        goal: s.goal,
 9258                        reversed: s.reversed,
 9259                    }
 9260                })
 9261                .collect();
 9262
 9263            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9264                s.select(new_selections);
 9265            });
 9266
 9267            this.request_autoscroll(Autoscroll::fit(), cx);
 9268        });
 9269    }
 9270
 9271    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9272        self.manipulate_text(window, cx, |text| {
 9273            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9274            if has_upper_case_characters {
 9275                text.to_lowercase()
 9276            } else {
 9277                text.to_uppercase()
 9278            }
 9279        })
 9280    }
 9281
 9282    pub fn convert_to_upper_case(
 9283        &mut self,
 9284        _: &ConvertToUpperCase,
 9285        window: &mut Window,
 9286        cx: &mut Context<Self>,
 9287    ) {
 9288        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9289    }
 9290
 9291    pub fn convert_to_lower_case(
 9292        &mut self,
 9293        _: &ConvertToLowerCase,
 9294        window: &mut Window,
 9295        cx: &mut Context<Self>,
 9296    ) {
 9297        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9298    }
 9299
 9300    pub fn convert_to_title_case(
 9301        &mut self,
 9302        _: &ConvertToTitleCase,
 9303        window: &mut Window,
 9304        cx: &mut Context<Self>,
 9305    ) {
 9306        self.manipulate_text(window, cx, |text| {
 9307            text.split('\n')
 9308                .map(|line| line.to_case(Case::Title))
 9309                .join("\n")
 9310        })
 9311    }
 9312
 9313    pub fn convert_to_snake_case(
 9314        &mut self,
 9315        _: &ConvertToSnakeCase,
 9316        window: &mut Window,
 9317        cx: &mut Context<Self>,
 9318    ) {
 9319        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 9320    }
 9321
 9322    pub fn convert_to_kebab_case(
 9323        &mut self,
 9324        _: &ConvertToKebabCase,
 9325        window: &mut Window,
 9326        cx: &mut Context<Self>,
 9327    ) {
 9328        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 9329    }
 9330
 9331    pub fn convert_to_upper_camel_case(
 9332        &mut self,
 9333        _: &ConvertToUpperCamelCase,
 9334        window: &mut Window,
 9335        cx: &mut Context<Self>,
 9336    ) {
 9337        self.manipulate_text(window, cx, |text| {
 9338            text.split('\n')
 9339                .map(|line| line.to_case(Case::UpperCamel))
 9340                .join("\n")
 9341        })
 9342    }
 9343
 9344    pub fn convert_to_lower_camel_case(
 9345        &mut self,
 9346        _: &ConvertToLowerCamelCase,
 9347        window: &mut Window,
 9348        cx: &mut Context<Self>,
 9349    ) {
 9350        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 9351    }
 9352
 9353    pub fn convert_to_opposite_case(
 9354        &mut self,
 9355        _: &ConvertToOppositeCase,
 9356        window: &mut Window,
 9357        cx: &mut Context<Self>,
 9358    ) {
 9359        self.manipulate_text(window, cx, |text| {
 9360            text.chars()
 9361                .fold(String::with_capacity(text.len()), |mut t, c| {
 9362                    if c.is_uppercase() {
 9363                        t.extend(c.to_lowercase());
 9364                    } else {
 9365                        t.extend(c.to_uppercase());
 9366                    }
 9367                    t
 9368                })
 9369        })
 9370    }
 9371
 9372    pub fn convert_to_rot13(
 9373        &mut self,
 9374        _: &ConvertToRot13,
 9375        window: &mut Window,
 9376        cx: &mut Context<Self>,
 9377    ) {
 9378        self.manipulate_text(window, cx, |text| {
 9379            text.chars()
 9380                .map(|c| match c {
 9381                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
 9382                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
 9383                    _ => c,
 9384                })
 9385                .collect()
 9386        })
 9387    }
 9388
 9389    pub fn convert_to_rot47(
 9390        &mut self,
 9391        _: &ConvertToRot47,
 9392        window: &mut Window,
 9393        cx: &mut Context<Self>,
 9394    ) {
 9395        self.manipulate_text(window, cx, |text| {
 9396            text.chars()
 9397                .map(|c| {
 9398                    let code_point = c as u32;
 9399                    if code_point >= 33 && code_point <= 126 {
 9400                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
 9401                    }
 9402                    c
 9403                })
 9404                .collect()
 9405        })
 9406    }
 9407
 9408    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 9409    where
 9410        Fn: FnMut(&str) -> String,
 9411    {
 9412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9413        let buffer = self.buffer.read(cx).snapshot(cx);
 9414
 9415        let mut new_selections = Vec::new();
 9416        let mut edits = Vec::new();
 9417        let mut selection_adjustment = 0i32;
 9418
 9419        for selection in self.selections.all::<usize>(cx) {
 9420            let selection_is_empty = selection.is_empty();
 9421
 9422            let (start, end) = if selection_is_empty {
 9423                let word_range = movement::surrounding_word(
 9424                    &display_map,
 9425                    selection.start.to_display_point(&display_map),
 9426                );
 9427                let start = word_range.start.to_offset(&display_map, Bias::Left);
 9428                let end = word_range.end.to_offset(&display_map, Bias::Left);
 9429                (start, end)
 9430            } else {
 9431                (selection.start, selection.end)
 9432            };
 9433
 9434            let text = buffer.text_for_range(start..end).collect::<String>();
 9435            let old_length = text.len() as i32;
 9436            let text = callback(&text);
 9437
 9438            new_selections.push(Selection {
 9439                start: (start as i32 - selection_adjustment) as usize,
 9440                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 9441                goal: SelectionGoal::None,
 9442                ..selection
 9443            });
 9444
 9445            selection_adjustment += old_length - text.len() as i32;
 9446
 9447            edits.push((start..end, text));
 9448        }
 9449
 9450        self.transact(window, cx, |this, window, cx| {
 9451            this.buffer.update(cx, |buffer, cx| {
 9452                buffer.edit(edits, None, cx);
 9453            });
 9454
 9455            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9456                s.select(new_selections);
 9457            });
 9458
 9459            this.request_autoscroll(Autoscroll::fit(), cx);
 9460        });
 9461    }
 9462
 9463    pub fn duplicate(
 9464        &mut self,
 9465        upwards: bool,
 9466        whole_lines: bool,
 9467        window: &mut Window,
 9468        cx: &mut Context<Self>,
 9469    ) {
 9470        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9471
 9472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9473        let buffer = &display_map.buffer_snapshot;
 9474        let selections = self.selections.all::<Point>(cx);
 9475
 9476        let mut edits = Vec::new();
 9477        let mut selections_iter = selections.iter().peekable();
 9478        while let Some(selection) = selections_iter.next() {
 9479            let mut rows = selection.spanned_rows(false, &display_map);
 9480            // duplicate line-wise
 9481            if whole_lines || selection.start == selection.end {
 9482                // Avoid duplicating the same lines twice.
 9483                while let Some(next_selection) = selections_iter.peek() {
 9484                    let next_rows = next_selection.spanned_rows(false, &display_map);
 9485                    if next_rows.start < rows.end {
 9486                        rows.end = next_rows.end;
 9487                        selections_iter.next().unwrap();
 9488                    } else {
 9489                        break;
 9490                    }
 9491                }
 9492
 9493                // Copy the text from the selected row region and splice it either at the start
 9494                // or end of the region.
 9495                let start = Point::new(rows.start.0, 0);
 9496                let end = Point::new(
 9497                    rows.end.previous_row().0,
 9498                    buffer.line_len(rows.end.previous_row()),
 9499                );
 9500                let text = buffer
 9501                    .text_for_range(start..end)
 9502                    .chain(Some("\n"))
 9503                    .collect::<String>();
 9504                let insert_location = if upwards {
 9505                    Point::new(rows.end.0, 0)
 9506                } else {
 9507                    start
 9508                };
 9509                edits.push((insert_location..insert_location, text));
 9510            } else {
 9511                // duplicate character-wise
 9512                let start = selection.start;
 9513                let end = selection.end;
 9514                let text = buffer.text_for_range(start..end).collect::<String>();
 9515                edits.push((selection.end..selection.end, text));
 9516            }
 9517        }
 9518
 9519        self.transact(window, cx, |this, _, cx| {
 9520            this.buffer.update(cx, |buffer, cx| {
 9521                buffer.edit(edits, None, cx);
 9522            });
 9523
 9524            this.request_autoscroll(Autoscroll::fit(), cx);
 9525        });
 9526    }
 9527
 9528    pub fn duplicate_line_up(
 9529        &mut self,
 9530        _: &DuplicateLineUp,
 9531        window: &mut Window,
 9532        cx: &mut Context<Self>,
 9533    ) {
 9534        self.duplicate(true, true, window, cx);
 9535    }
 9536
 9537    pub fn duplicate_line_down(
 9538        &mut self,
 9539        _: &DuplicateLineDown,
 9540        window: &mut Window,
 9541        cx: &mut Context<Self>,
 9542    ) {
 9543        self.duplicate(false, true, window, cx);
 9544    }
 9545
 9546    pub fn duplicate_selection(
 9547        &mut self,
 9548        _: &DuplicateSelection,
 9549        window: &mut Window,
 9550        cx: &mut Context<Self>,
 9551    ) {
 9552        self.duplicate(false, false, window, cx);
 9553    }
 9554
 9555    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
 9556        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9557
 9558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9559        let buffer = self.buffer.read(cx).snapshot(cx);
 9560
 9561        let mut edits = Vec::new();
 9562        let mut unfold_ranges = Vec::new();
 9563        let mut refold_creases = Vec::new();
 9564
 9565        let selections = self.selections.all::<Point>(cx);
 9566        let mut selections = selections.iter().peekable();
 9567        let mut contiguous_row_selections = Vec::new();
 9568        let mut new_selections = Vec::new();
 9569
 9570        while let Some(selection) = selections.next() {
 9571            // Find all the selections that span a contiguous row range
 9572            let (start_row, end_row) = consume_contiguous_rows(
 9573                &mut contiguous_row_selections,
 9574                selection,
 9575                &display_map,
 9576                &mut selections,
 9577            );
 9578
 9579            // Move the text spanned by the row range to be before the line preceding the row range
 9580            if start_row.0 > 0 {
 9581                let range_to_move = Point::new(
 9582                    start_row.previous_row().0,
 9583                    buffer.line_len(start_row.previous_row()),
 9584                )
 9585                    ..Point::new(
 9586                        end_row.previous_row().0,
 9587                        buffer.line_len(end_row.previous_row()),
 9588                    );
 9589                let insertion_point = display_map
 9590                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 9591                    .0;
 9592
 9593                // Don't move lines across excerpts
 9594                if buffer
 9595                    .excerpt_containing(insertion_point..range_to_move.end)
 9596                    .is_some()
 9597                {
 9598                    let text = buffer
 9599                        .text_for_range(range_to_move.clone())
 9600                        .flat_map(|s| s.chars())
 9601                        .skip(1)
 9602                        .chain(['\n'])
 9603                        .collect::<String>();
 9604
 9605                    edits.push((
 9606                        buffer.anchor_after(range_to_move.start)
 9607                            ..buffer.anchor_before(range_to_move.end),
 9608                        String::new(),
 9609                    ));
 9610                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9611                    edits.push((insertion_anchor..insertion_anchor, text));
 9612
 9613                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 9614
 9615                    // Move selections up
 9616                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9617                        |mut selection| {
 9618                            selection.start.row -= row_delta;
 9619                            selection.end.row -= row_delta;
 9620                            selection
 9621                        },
 9622                    ));
 9623
 9624                    // Move folds up
 9625                    unfold_ranges.push(range_to_move.clone());
 9626                    for fold in display_map.folds_in_range(
 9627                        buffer.anchor_before(range_to_move.start)
 9628                            ..buffer.anchor_after(range_to_move.end),
 9629                    ) {
 9630                        let mut start = fold.range.start.to_point(&buffer);
 9631                        let mut end = fold.range.end.to_point(&buffer);
 9632                        start.row -= row_delta;
 9633                        end.row -= row_delta;
 9634                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9635                    }
 9636                }
 9637            }
 9638
 9639            // If we didn't move line(s), preserve the existing selections
 9640            new_selections.append(&mut contiguous_row_selections);
 9641        }
 9642
 9643        self.transact(window, cx, |this, window, cx| {
 9644            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9645            this.buffer.update(cx, |buffer, cx| {
 9646                for (range, text) in edits {
 9647                    buffer.edit([(range, text)], None, cx);
 9648                }
 9649            });
 9650            this.fold_creases(refold_creases, true, window, cx);
 9651            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9652                s.select(new_selections);
 9653            })
 9654        });
 9655    }
 9656
 9657    pub fn move_line_down(
 9658        &mut self,
 9659        _: &MoveLineDown,
 9660        window: &mut Window,
 9661        cx: &mut Context<Self>,
 9662    ) {
 9663        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9664
 9665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9666        let buffer = self.buffer.read(cx).snapshot(cx);
 9667
 9668        let mut edits = Vec::new();
 9669        let mut unfold_ranges = Vec::new();
 9670        let mut refold_creases = Vec::new();
 9671
 9672        let selections = self.selections.all::<Point>(cx);
 9673        let mut selections = selections.iter().peekable();
 9674        let mut contiguous_row_selections = Vec::new();
 9675        let mut new_selections = Vec::new();
 9676
 9677        while let Some(selection) = selections.next() {
 9678            // Find all the selections that span a contiguous row range
 9679            let (start_row, end_row) = consume_contiguous_rows(
 9680                &mut contiguous_row_selections,
 9681                selection,
 9682                &display_map,
 9683                &mut selections,
 9684            );
 9685
 9686            // Move the text spanned by the row range to be after the last line of the row range
 9687            if end_row.0 <= buffer.max_point().row {
 9688                let range_to_move =
 9689                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 9690                let insertion_point = display_map
 9691                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 9692                    .0;
 9693
 9694                // Don't move lines across excerpt boundaries
 9695                if buffer
 9696                    .excerpt_containing(range_to_move.start..insertion_point)
 9697                    .is_some()
 9698                {
 9699                    let mut text = String::from("\n");
 9700                    text.extend(buffer.text_for_range(range_to_move.clone()));
 9701                    text.pop(); // Drop trailing newline
 9702                    edits.push((
 9703                        buffer.anchor_after(range_to_move.start)
 9704                            ..buffer.anchor_before(range_to_move.end),
 9705                        String::new(),
 9706                    ));
 9707                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9708                    edits.push((insertion_anchor..insertion_anchor, text));
 9709
 9710                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 9711
 9712                    // Move selections down
 9713                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9714                        |mut selection| {
 9715                            selection.start.row += row_delta;
 9716                            selection.end.row += row_delta;
 9717                            selection
 9718                        },
 9719                    ));
 9720
 9721                    // Move folds down
 9722                    unfold_ranges.push(range_to_move.clone());
 9723                    for fold in display_map.folds_in_range(
 9724                        buffer.anchor_before(range_to_move.start)
 9725                            ..buffer.anchor_after(range_to_move.end),
 9726                    ) {
 9727                        let mut start = fold.range.start.to_point(&buffer);
 9728                        let mut end = fold.range.end.to_point(&buffer);
 9729                        start.row += row_delta;
 9730                        end.row += row_delta;
 9731                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9732                    }
 9733                }
 9734            }
 9735
 9736            // If we didn't move line(s), preserve the existing selections
 9737            new_selections.append(&mut contiguous_row_selections);
 9738        }
 9739
 9740        self.transact(window, cx, |this, window, cx| {
 9741            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9742            this.buffer.update(cx, |buffer, cx| {
 9743                for (range, text) in edits {
 9744                    buffer.edit([(range, text)], None, cx);
 9745                }
 9746            });
 9747            this.fold_creases(refold_creases, true, window, cx);
 9748            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9749                s.select(new_selections)
 9750            });
 9751        });
 9752    }
 9753
 9754    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
 9755        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9756        let text_layout_details = &self.text_layout_details(window);
 9757        self.transact(window, cx, |this, window, cx| {
 9758            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9759                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 9760                s.move_with(|display_map, selection| {
 9761                    if !selection.is_empty() {
 9762                        return;
 9763                    }
 9764
 9765                    let mut head = selection.head();
 9766                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 9767                    if head.column() == display_map.line_len(head.row()) {
 9768                        transpose_offset = display_map
 9769                            .buffer_snapshot
 9770                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 9771                    }
 9772
 9773                    if transpose_offset == 0 {
 9774                        return;
 9775                    }
 9776
 9777                    *head.column_mut() += 1;
 9778                    head = display_map.clip_point(head, Bias::Right);
 9779                    let goal = SelectionGoal::HorizontalPosition(
 9780                        display_map
 9781                            .x_for_display_point(head, text_layout_details)
 9782                            .into(),
 9783                    );
 9784                    selection.collapse_to(head, goal);
 9785
 9786                    let transpose_start = display_map
 9787                        .buffer_snapshot
 9788                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 9789                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 9790                        let transpose_end = display_map
 9791                            .buffer_snapshot
 9792                            .clip_offset(transpose_offset + 1, Bias::Right);
 9793                        if let Some(ch) =
 9794                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 9795                        {
 9796                            edits.push((transpose_start..transpose_offset, String::new()));
 9797                            edits.push((transpose_end..transpose_end, ch.to_string()));
 9798                        }
 9799                    }
 9800                });
 9801                edits
 9802            });
 9803            this.buffer
 9804                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 9805            let selections = this.selections.all::<usize>(cx);
 9806            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9807                s.select(selections);
 9808            });
 9809        });
 9810    }
 9811
 9812    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
 9813        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9814        self.rewrap_impl(RewrapOptions::default(), cx)
 9815    }
 9816
 9817    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
 9818        let buffer = self.buffer.read(cx).snapshot(cx);
 9819        let selections = self.selections.all::<Point>(cx);
 9820        let mut selections = selections.iter().peekable();
 9821
 9822        let mut edits = Vec::new();
 9823        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
 9824
 9825        while let Some(selection) = selections.next() {
 9826            let mut start_row = selection.start.row;
 9827            let mut end_row = selection.end.row;
 9828
 9829            // Skip selections that overlap with a range that has already been rewrapped.
 9830            let selection_range = start_row..end_row;
 9831            if rewrapped_row_ranges
 9832                .iter()
 9833                .any(|range| range.overlaps(&selection_range))
 9834            {
 9835                continue;
 9836            }
 9837
 9838            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
 9839
 9840            // Since not all lines in the selection may be at the same indent
 9841            // level, choose the indent size that is the most common between all
 9842            // of the lines.
 9843            //
 9844            // If there is a tie, we use the deepest indent.
 9845            let (indent_size, indent_end) = {
 9846                let mut indent_size_occurrences = HashMap::default();
 9847                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
 9848
 9849                for row in start_row..=end_row {
 9850                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
 9851                    rows_by_indent_size.entry(indent).or_default().push(row);
 9852                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
 9853                }
 9854
 9855                let indent_size = indent_size_occurrences
 9856                    .into_iter()
 9857                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
 9858                    .map(|(indent, _)| indent)
 9859                    .unwrap_or_default();
 9860                let row = rows_by_indent_size[&indent_size][0];
 9861                let indent_end = Point::new(row, indent_size.len);
 9862
 9863                (indent_size, indent_end)
 9864            };
 9865
 9866            let mut line_prefix = indent_size.chars().collect::<String>();
 9867
 9868            let mut inside_comment = false;
 9869            if let Some(comment_prefix) =
 9870                buffer
 9871                    .language_scope_at(selection.head())
 9872                    .and_then(|language| {
 9873                        language
 9874                            .line_comment_prefixes()
 9875                            .iter()
 9876                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
 9877                            .cloned()
 9878                    })
 9879            {
 9880                line_prefix.push_str(&comment_prefix);
 9881                inside_comment = true;
 9882            }
 9883
 9884            let language_settings = buffer.language_settings_at(selection.head(), cx);
 9885            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
 9886                RewrapBehavior::InComments => inside_comment,
 9887                RewrapBehavior::InSelections => !selection.is_empty(),
 9888                RewrapBehavior::Anywhere => true,
 9889            };
 9890
 9891            let should_rewrap = options.override_language_settings
 9892                || allow_rewrap_based_on_language
 9893                || self.hard_wrap.is_some();
 9894            if !should_rewrap {
 9895                continue;
 9896            }
 9897
 9898            if selection.is_empty() {
 9899                'expand_upwards: while start_row > 0 {
 9900                    let prev_row = start_row - 1;
 9901                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
 9902                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
 9903                    {
 9904                        start_row = prev_row;
 9905                    } else {
 9906                        break 'expand_upwards;
 9907                    }
 9908                }
 9909
 9910                'expand_downwards: while end_row < buffer.max_point().row {
 9911                    let next_row = end_row + 1;
 9912                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
 9913                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
 9914                    {
 9915                        end_row = next_row;
 9916                    } else {
 9917                        break 'expand_downwards;
 9918                    }
 9919                }
 9920            }
 9921
 9922            let start = Point::new(start_row, 0);
 9923            let start_offset = start.to_offset(&buffer);
 9924            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
 9925            let selection_text = buffer.text_for_range(start..end).collect::<String>();
 9926            let Some(lines_without_prefixes) = selection_text
 9927                .lines()
 9928                .map(|line| {
 9929                    line.strip_prefix(&line_prefix)
 9930                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
 9931                        .ok_or_else(|| {
 9932                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
 9933                        })
 9934                })
 9935                .collect::<Result<Vec<_>, _>>()
 9936                .log_err()
 9937            else {
 9938                continue;
 9939            };
 9940
 9941            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
 9942                buffer
 9943                    .language_settings_at(Point::new(start_row, 0), cx)
 9944                    .preferred_line_length as usize
 9945            });
 9946            let wrapped_text = wrap_with_prefix(
 9947                line_prefix,
 9948                lines_without_prefixes.join("\n"),
 9949                wrap_column,
 9950                tab_size,
 9951                options.preserve_existing_whitespace,
 9952            );
 9953
 9954            // TODO: should always use char-based diff while still supporting cursor behavior that
 9955            // matches vim.
 9956            let mut diff_options = DiffOptions::default();
 9957            if options.override_language_settings {
 9958                diff_options.max_word_diff_len = 0;
 9959                diff_options.max_word_diff_line_count = 0;
 9960            } else {
 9961                diff_options.max_word_diff_len = usize::MAX;
 9962                diff_options.max_word_diff_line_count = usize::MAX;
 9963            }
 9964
 9965            for (old_range, new_text) in
 9966                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
 9967            {
 9968                let edit_start = buffer.anchor_after(start_offset + old_range.start);
 9969                let edit_end = buffer.anchor_after(start_offset + old_range.end);
 9970                edits.push((edit_start..edit_end, new_text));
 9971            }
 9972
 9973            rewrapped_row_ranges.push(start_row..=end_row);
 9974        }
 9975
 9976        self.buffer
 9977            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 9978    }
 9979
 9980    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
 9981        let mut text = String::new();
 9982        let buffer = self.buffer.read(cx).snapshot(cx);
 9983        let mut selections = self.selections.all::<Point>(cx);
 9984        let mut clipboard_selections = Vec::with_capacity(selections.len());
 9985        {
 9986            let max_point = buffer.max_point();
 9987            let mut is_first = true;
 9988            for selection in &mut selections {
 9989                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 9990                if is_entire_line {
 9991                    selection.start = Point::new(selection.start.row, 0);
 9992                    if !selection.is_empty() && selection.end.column == 0 {
 9993                        selection.end = cmp::min(max_point, selection.end);
 9994                    } else {
 9995                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 9996                    }
 9997                    selection.goal = SelectionGoal::None;
 9998                }
 9999                if is_first {
10000                    is_first = false;
10001                } else {
10002                    text += "\n";
10003                }
10004                let mut len = 0;
10005                for chunk in buffer.text_for_range(selection.start..selection.end) {
10006                    text.push_str(chunk);
10007                    len += chunk.len();
10008                }
10009                clipboard_selections.push(ClipboardSelection {
10010                    len,
10011                    is_entire_line,
10012                    first_line_indent: buffer
10013                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10014                        .len,
10015                });
10016            }
10017        }
10018
10019        self.transact(window, cx, |this, window, cx| {
10020            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10021                s.select(selections);
10022            });
10023            this.insert("", window, cx);
10024        });
10025        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10026    }
10027
10028    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10029        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10030        let item = self.cut_common(window, cx);
10031        cx.write_to_clipboard(item);
10032    }
10033
10034    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10035        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10036        self.change_selections(None, window, cx, |s| {
10037            s.move_with(|snapshot, sel| {
10038                if sel.is_empty() {
10039                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10040                }
10041            });
10042        });
10043        let item = self.cut_common(window, cx);
10044        cx.set_global(KillRing(item))
10045    }
10046
10047    pub fn kill_ring_yank(
10048        &mut self,
10049        _: &KillRingYank,
10050        window: &mut Window,
10051        cx: &mut Context<Self>,
10052    ) {
10053        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10054        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10055            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10056                (kill_ring.text().to_string(), kill_ring.metadata_json())
10057            } else {
10058                return;
10059            }
10060        } else {
10061            return;
10062        };
10063        self.do_paste(&text, metadata, false, window, cx);
10064    }
10065
10066    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10067        self.do_copy(true, cx);
10068    }
10069
10070    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10071        self.do_copy(false, cx);
10072    }
10073
10074    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10075        let selections = self.selections.all::<Point>(cx);
10076        let buffer = self.buffer.read(cx).read(cx);
10077        let mut text = String::new();
10078
10079        let mut clipboard_selections = Vec::with_capacity(selections.len());
10080        {
10081            let max_point = buffer.max_point();
10082            let mut is_first = true;
10083            for selection in &selections {
10084                let mut start = selection.start;
10085                let mut end = selection.end;
10086                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10087                if is_entire_line {
10088                    start = Point::new(start.row, 0);
10089                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10090                }
10091
10092                let mut trimmed_selections = Vec::new();
10093                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10094                    let row = MultiBufferRow(start.row);
10095                    let first_indent = buffer.indent_size_for_line(row);
10096                    if first_indent.len == 0 || start.column > first_indent.len {
10097                        trimmed_selections.push(start..end);
10098                    } else {
10099                        trimmed_selections.push(
10100                            Point::new(row.0, first_indent.len)
10101                                ..Point::new(row.0, buffer.line_len(row)),
10102                        );
10103                        for row in start.row + 1..=end.row {
10104                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10105                            if row_indent_size.len >= first_indent.len {
10106                                trimmed_selections.push(
10107                                    Point::new(row, first_indent.len)
10108                                        ..Point::new(row, buffer.line_len(MultiBufferRow(row))),
10109                                );
10110                            } else {
10111                                trimmed_selections.clear();
10112                                trimmed_selections.push(start..end);
10113                                break;
10114                            }
10115                        }
10116                    }
10117                } else {
10118                    trimmed_selections.push(start..end);
10119                }
10120
10121                for trimmed_range in trimmed_selections {
10122                    if is_first {
10123                        is_first = false;
10124                    } else {
10125                        text += "\n";
10126                    }
10127                    let mut len = 0;
10128                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10129                        text.push_str(chunk);
10130                        len += chunk.len();
10131                    }
10132                    clipboard_selections.push(ClipboardSelection {
10133                        len,
10134                        is_entire_line,
10135                        first_line_indent: buffer
10136                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10137                            .len,
10138                    });
10139                }
10140            }
10141        }
10142
10143        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10144            text,
10145            clipboard_selections,
10146        ));
10147    }
10148
10149    pub fn do_paste(
10150        &mut self,
10151        text: &String,
10152        clipboard_selections: Option<Vec<ClipboardSelection>>,
10153        handle_entire_lines: bool,
10154        window: &mut Window,
10155        cx: &mut Context<Self>,
10156    ) {
10157        if self.read_only(cx) {
10158            return;
10159        }
10160
10161        let clipboard_text = Cow::Borrowed(text);
10162
10163        self.transact(window, cx, |this, window, cx| {
10164            if let Some(mut clipboard_selections) = clipboard_selections {
10165                let old_selections = this.selections.all::<usize>(cx);
10166                let all_selections_were_entire_line =
10167                    clipboard_selections.iter().all(|s| s.is_entire_line);
10168                let first_selection_indent_column =
10169                    clipboard_selections.first().map(|s| s.first_line_indent);
10170                if clipboard_selections.len() != old_selections.len() {
10171                    clipboard_selections.drain(..);
10172                }
10173                let cursor_offset = this.selections.last::<usize>(cx).head();
10174                let mut auto_indent_on_paste = true;
10175
10176                this.buffer.update(cx, |buffer, cx| {
10177                    let snapshot = buffer.read(cx);
10178                    auto_indent_on_paste = snapshot
10179                        .language_settings_at(cursor_offset, cx)
10180                        .auto_indent_on_paste;
10181
10182                    let mut start_offset = 0;
10183                    let mut edits = Vec::new();
10184                    let mut original_indent_columns = Vec::new();
10185                    for (ix, selection) in old_selections.iter().enumerate() {
10186                        let to_insert;
10187                        let entire_line;
10188                        let original_indent_column;
10189                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10190                            let end_offset = start_offset + clipboard_selection.len;
10191                            to_insert = &clipboard_text[start_offset..end_offset];
10192                            entire_line = clipboard_selection.is_entire_line;
10193                            start_offset = end_offset + 1;
10194                            original_indent_column = Some(clipboard_selection.first_line_indent);
10195                        } else {
10196                            to_insert = clipboard_text.as_str();
10197                            entire_line = all_selections_were_entire_line;
10198                            original_indent_column = first_selection_indent_column
10199                        }
10200
10201                        // If the corresponding selection was empty when this slice of the
10202                        // clipboard text was written, then the entire line containing the
10203                        // selection was copied. If this selection is also currently empty,
10204                        // then paste the line before the current line of the buffer.
10205                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10206                            let column = selection.start.to_point(&snapshot).column as usize;
10207                            let line_start = selection.start - column;
10208                            line_start..line_start
10209                        } else {
10210                            selection.range()
10211                        };
10212
10213                        edits.push((range, to_insert));
10214                        original_indent_columns.push(original_indent_column);
10215                    }
10216                    drop(snapshot);
10217
10218                    buffer.edit(
10219                        edits,
10220                        if auto_indent_on_paste {
10221                            Some(AutoindentMode::Block {
10222                                original_indent_columns,
10223                            })
10224                        } else {
10225                            None
10226                        },
10227                        cx,
10228                    );
10229                });
10230
10231                let selections = this.selections.all::<usize>(cx);
10232                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10233                    s.select(selections)
10234                });
10235            } else {
10236                this.insert(&clipboard_text, window, cx);
10237            }
10238        });
10239    }
10240
10241    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10242        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10243        if let Some(item) = cx.read_from_clipboard() {
10244            let entries = item.entries();
10245
10246            match entries.first() {
10247                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10248                // of all the pasted entries.
10249                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10250                    .do_paste(
10251                        clipboard_string.text(),
10252                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10253                        true,
10254                        window,
10255                        cx,
10256                    ),
10257                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10258            }
10259        }
10260    }
10261
10262    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10263        if self.read_only(cx) {
10264            return;
10265        }
10266
10267        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10268
10269        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10270            if let Some((selections, _)) =
10271                self.selection_history.transaction(transaction_id).cloned()
10272            {
10273                self.change_selections(None, window, cx, |s| {
10274                    s.select_anchors(selections.to_vec());
10275                });
10276            } else {
10277                log::error!(
10278                    "No entry in selection_history found for undo. \
10279                     This may correspond to a bug where undo does not update the selection. \
10280                     If this is occurring, please add details to \
10281                     https://github.com/zed-industries/zed/issues/22692"
10282                );
10283            }
10284            self.request_autoscroll(Autoscroll::fit(), cx);
10285            self.unmark_text(window, cx);
10286            self.refresh_inline_completion(true, false, window, cx);
10287            cx.emit(EditorEvent::Edited { transaction_id });
10288            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10289        }
10290    }
10291
10292    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10293        if self.read_only(cx) {
10294            return;
10295        }
10296
10297        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10298
10299        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10300            if let Some((_, Some(selections))) =
10301                self.selection_history.transaction(transaction_id).cloned()
10302            {
10303                self.change_selections(None, window, cx, |s| {
10304                    s.select_anchors(selections.to_vec());
10305                });
10306            } else {
10307                log::error!(
10308                    "No entry in selection_history found for redo. \
10309                     This may correspond to a bug where undo does not update the selection. \
10310                     If this is occurring, please add details to \
10311                     https://github.com/zed-industries/zed/issues/22692"
10312                );
10313            }
10314            self.request_autoscroll(Autoscroll::fit(), cx);
10315            self.unmark_text(window, cx);
10316            self.refresh_inline_completion(true, false, window, cx);
10317            cx.emit(EditorEvent::Edited { transaction_id });
10318        }
10319    }
10320
10321    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
10322        self.buffer
10323            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
10324    }
10325
10326    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
10327        self.buffer
10328            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
10329    }
10330
10331    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
10332        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10333        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10334            s.move_with(|map, selection| {
10335                let cursor = if selection.is_empty() {
10336                    movement::left(map, selection.start)
10337                } else {
10338                    selection.start
10339                };
10340                selection.collapse_to(cursor, SelectionGoal::None);
10341            });
10342        })
10343    }
10344
10345    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
10346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10347        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10348            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
10349        })
10350    }
10351
10352    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
10353        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10355            s.move_with(|map, selection| {
10356                let cursor = if selection.is_empty() {
10357                    movement::right(map, selection.end)
10358                } else {
10359                    selection.end
10360                };
10361                selection.collapse_to(cursor, SelectionGoal::None)
10362            });
10363        })
10364    }
10365
10366    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
10367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10369            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
10370        })
10371    }
10372
10373    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
10374        if self.take_rename(true, window, cx).is_some() {
10375            return;
10376        }
10377
10378        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10379            cx.propagate();
10380            return;
10381        }
10382
10383        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10384
10385        let text_layout_details = &self.text_layout_details(window);
10386        let selection_count = self.selections.count();
10387        let first_selection = self.selections.first_anchor();
10388
10389        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10390            s.move_with(|map, selection| {
10391                if !selection.is_empty() {
10392                    selection.goal = SelectionGoal::None;
10393                }
10394                let (cursor, goal) = movement::up(
10395                    map,
10396                    selection.start,
10397                    selection.goal,
10398                    false,
10399                    text_layout_details,
10400                );
10401                selection.collapse_to(cursor, goal);
10402            });
10403        });
10404
10405        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10406        {
10407            cx.propagate();
10408        }
10409    }
10410
10411    pub fn move_up_by_lines(
10412        &mut self,
10413        action: &MoveUpByLines,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        if self.take_rename(true, window, cx).is_some() {
10418            return;
10419        }
10420
10421        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10422            cx.propagate();
10423            return;
10424        }
10425
10426        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10427
10428        let text_layout_details = &self.text_layout_details(window);
10429
10430        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10431            s.move_with(|map, selection| {
10432                if !selection.is_empty() {
10433                    selection.goal = SelectionGoal::None;
10434                }
10435                let (cursor, goal) = movement::up_by_rows(
10436                    map,
10437                    selection.start,
10438                    action.lines,
10439                    selection.goal,
10440                    false,
10441                    text_layout_details,
10442                );
10443                selection.collapse_to(cursor, goal);
10444            });
10445        })
10446    }
10447
10448    pub fn move_down_by_lines(
10449        &mut self,
10450        action: &MoveDownByLines,
10451        window: &mut Window,
10452        cx: &mut Context<Self>,
10453    ) {
10454        if self.take_rename(true, window, cx).is_some() {
10455            return;
10456        }
10457
10458        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10459            cx.propagate();
10460            return;
10461        }
10462
10463        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10464
10465        let text_layout_details = &self.text_layout_details(window);
10466
10467        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10468            s.move_with(|map, selection| {
10469                if !selection.is_empty() {
10470                    selection.goal = SelectionGoal::None;
10471                }
10472                let (cursor, goal) = movement::down_by_rows(
10473                    map,
10474                    selection.start,
10475                    action.lines,
10476                    selection.goal,
10477                    false,
10478                    text_layout_details,
10479                );
10480                selection.collapse_to(cursor, goal);
10481            });
10482        })
10483    }
10484
10485    pub fn select_down_by_lines(
10486        &mut self,
10487        action: &SelectDownByLines,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10492        let text_layout_details = &self.text_layout_details(window);
10493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10494            s.move_heads_with(|map, head, goal| {
10495                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
10496            })
10497        })
10498    }
10499
10500    pub fn select_up_by_lines(
10501        &mut self,
10502        action: &SelectUpByLines,
10503        window: &mut Window,
10504        cx: &mut Context<Self>,
10505    ) {
10506        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10507        let text_layout_details = &self.text_layout_details(window);
10508        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10509            s.move_heads_with(|map, head, goal| {
10510                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
10511            })
10512        })
10513    }
10514
10515    pub fn select_page_up(
10516        &mut self,
10517        _: &SelectPageUp,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        let Some(row_count) = self.visible_row_count() else {
10522            return;
10523        };
10524
10525        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10526
10527        let text_layout_details = &self.text_layout_details(window);
10528
10529        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10530            s.move_heads_with(|map, head, goal| {
10531                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
10532            })
10533        })
10534    }
10535
10536    pub fn move_page_up(
10537        &mut self,
10538        action: &MovePageUp,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541    ) {
10542        if self.take_rename(true, window, cx).is_some() {
10543            return;
10544        }
10545
10546        if self
10547            .context_menu
10548            .borrow_mut()
10549            .as_mut()
10550            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
10551            .unwrap_or(false)
10552        {
10553            return;
10554        }
10555
10556        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10557            cx.propagate();
10558            return;
10559        }
10560
10561        let Some(row_count) = self.visible_row_count() else {
10562            return;
10563        };
10564
10565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10566
10567        let autoscroll = if action.center_cursor {
10568            Autoscroll::center()
10569        } else {
10570            Autoscroll::fit()
10571        };
10572
10573        let text_layout_details = &self.text_layout_details(window);
10574
10575        self.change_selections(Some(autoscroll), window, cx, |s| {
10576            s.move_with(|map, selection| {
10577                if !selection.is_empty() {
10578                    selection.goal = SelectionGoal::None;
10579                }
10580                let (cursor, goal) = movement::up_by_rows(
10581                    map,
10582                    selection.end,
10583                    row_count,
10584                    selection.goal,
10585                    false,
10586                    text_layout_details,
10587                );
10588                selection.collapse_to(cursor, goal);
10589            });
10590        });
10591    }
10592
10593    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
10594        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10595        let text_layout_details = &self.text_layout_details(window);
10596        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10597            s.move_heads_with(|map, head, goal| {
10598                movement::up(map, head, goal, false, text_layout_details)
10599            })
10600        })
10601    }
10602
10603    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
10604        self.take_rename(true, window, cx);
10605
10606        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10607            cx.propagate();
10608            return;
10609        }
10610
10611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10612
10613        let text_layout_details = &self.text_layout_details(window);
10614        let selection_count = self.selections.count();
10615        let first_selection = self.selections.first_anchor();
10616
10617        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10618            s.move_with(|map, selection| {
10619                if !selection.is_empty() {
10620                    selection.goal = SelectionGoal::None;
10621                }
10622                let (cursor, goal) = movement::down(
10623                    map,
10624                    selection.end,
10625                    selection.goal,
10626                    false,
10627                    text_layout_details,
10628                );
10629                selection.collapse_to(cursor, goal);
10630            });
10631        });
10632
10633        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10634        {
10635            cx.propagate();
10636        }
10637    }
10638
10639    pub fn select_page_down(
10640        &mut self,
10641        _: &SelectPageDown,
10642        window: &mut Window,
10643        cx: &mut Context<Self>,
10644    ) {
10645        let Some(row_count) = self.visible_row_count() else {
10646            return;
10647        };
10648
10649        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10650
10651        let text_layout_details = &self.text_layout_details(window);
10652
10653        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10654            s.move_heads_with(|map, head, goal| {
10655                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
10656            })
10657        })
10658    }
10659
10660    pub fn move_page_down(
10661        &mut self,
10662        action: &MovePageDown,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        if self.take_rename(true, window, cx).is_some() {
10667            return;
10668        }
10669
10670        if self
10671            .context_menu
10672            .borrow_mut()
10673            .as_mut()
10674            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
10675            .unwrap_or(false)
10676        {
10677            return;
10678        }
10679
10680        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10681            cx.propagate();
10682            return;
10683        }
10684
10685        let Some(row_count) = self.visible_row_count() else {
10686            return;
10687        };
10688
10689        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10690
10691        let autoscroll = if action.center_cursor {
10692            Autoscroll::center()
10693        } else {
10694            Autoscroll::fit()
10695        };
10696
10697        let text_layout_details = &self.text_layout_details(window);
10698        self.change_selections(Some(autoscroll), window, cx, |s| {
10699            s.move_with(|map, selection| {
10700                if !selection.is_empty() {
10701                    selection.goal = SelectionGoal::None;
10702                }
10703                let (cursor, goal) = movement::down_by_rows(
10704                    map,
10705                    selection.end,
10706                    row_count,
10707                    selection.goal,
10708                    false,
10709                    text_layout_details,
10710                );
10711                selection.collapse_to(cursor, goal);
10712            });
10713        });
10714    }
10715
10716    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
10717        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10718        let text_layout_details = &self.text_layout_details(window);
10719        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10720            s.move_heads_with(|map, head, goal| {
10721                movement::down(map, head, goal, false, text_layout_details)
10722            })
10723        });
10724    }
10725
10726    pub fn context_menu_first(
10727        &mut self,
10728        _: &ContextMenuFirst,
10729        _window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10733            context_menu.select_first(self.completion_provider.as_deref(), cx);
10734        }
10735    }
10736
10737    pub fn context_menu_prev(
10738        &mut self,
10739        _: &ContextMenuPrevious,
10740        _window: &mut Window,
10741        cx: &mut Context<Self>,
10742    ) {
10743        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10744            context_menu.select_prev(self.completion_provider.as_deref(), cx);
10745        }
10746    }
10747
10748    pub fn context_menu_next(
10749        &mut self,
10750        _: &ContextMenuNext,
10751        _window: &mut Window,
10752        cx: &mut Context<Self>,
10753    ) {
10754        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10755            context_menu.select_next(self.completion_provider.as_deref(), cx);
10756        }
10757    }
10758
10759    pub fn context_menu_last(
10760        &mut self,
10761        _: &ContextMenuLast,
10762        _window: &mut Window,
10763        cx: &mut Context<Self>,
10764    ) {
10765        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10766            context_menu.select_last(self.completion_provider.as_deref(), cx);
10767        }
10768    }
10769
10770    pub fn move_to_previous_word_start(
10771        &mut self,
10772        _: &MoveToPreviousWordStart,
10773        window: &mut Window,
10774        cx: &mut Context<Self>,
10775    ) {
10776        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10777        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10778            s.move_cursors_with(|map, head, _| {
10779                (
10780                    movement::previous_word_start(map, head),
10781                    SelectionGoal::None,
10782                )
10783            });
10784        })
10785    }
10786
10787    pub fn move_to_previous_subword_start(
10788        &mut self,
10789        _: &MoveToPreviousSubwordStart,
10790        window: &mut Window,
10791        cx: &mut Context<Self>,
10792    ) {
10793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10795            s.move_cursors_with(|map, head, _| {
10796                (
10797                    movement::previous_subword_start(map, head),
10798                    SelectionGoal::None,
10799                )
10800            });
10801        })
10802    }
10803
10804    pub fn select_to_previous_word_start(
10805        &mut self,
10806        _: &SelectToPreviousWordStart,
10807        window: &mut Window,
10808        cx: &mut Context<Self>,
10809    ) {
10810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10811        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10812            s.move_heads_with(|map, head, _| {
10813                (
10814                    movement::previous_word_start(map, head),
10815                    SelectionGoal::None,
10816                )
10817            });
10818        })
10819    }
10820
10821    pub fn select_to_previous_subword_start(
10822        &mut self,
10823        _: &SelectToPreviousSubwordStart,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10828        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10829            s.move_heads_with(|map, head, _| {
10830                (
10831                    movement::previous_subword_start(map, head),
10832                    SelectionGoal::None,
10833                )
10834            });
10835        })
10836    }
10837
10838    pub fn delete_to_previous_word_start(
10839        &mut self,
10840        action: &DeleteToPreviousWordStart,
10841        window: &mut Window,
10842        cx: &mut Context<Self>,
10843    ) {
10844        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10845        self.transact(window, cx, |this, window, cx| {
10846            this.select_autoclose_pair(window, cx);
10847            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10848                s.move_with(|map, selection| {
10849                    if selection.is_empty() {
10850                        let cursor = if action.ignore_newlines {
10851                            movement::previous_word_start(map, selection.head())
10852                        } else {
10853                            movement::previous_word_start_or_newline(map, selection.head())
10854                        };
10855                        selection.set_head(cursor, SelectionGoal::None);
10856                    }
10857                });
10858            });
10859            this.insert("", window, cx);
10860        });
10861    }
10862
10863    pub fn delete_to_previous_subword_start(
10864        &mut self,
10865        _: &DeleteToPreviousSubwordStart,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10870        self.transact(window, cx, |this, window, cx| {
10871            this.select_autoclose_pair(window, cx);
10872            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10873                s.move_with(|map, selection| {
10874                    if selection.is_empty() {
10875                        let cursor = movement::previous_subword_start(map, selection.head());
10876                        selection.set_head(cursor, SelectionGoal::None);
10877                    }
10878                });
10879            });
10880            this.insert("", window, cx);
10881        });
10882    }
10883
10884    pub fn move_to_next_word_end(
10885        &mut self,
10886        _: &MoveToNextWordEnd,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10891        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10892            s.move_cursors_with(|map, head, _| {
10893                (movement::next_word_end(map, head), SelectionGoal::None)
10894            });
10895        })
10896    }
10897
10898    pub fn move_to_next_subword_end(
10899        &mut self,
10900        _: &MoveToNextSubwordEnd,
10901        window: &mut Window,
10902        cx: &mut Context<Self>,
10903    ) {
10904        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10905        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10906            s.move_cursors_with(|map, head, _| {
10907                (movement::next_subword_end(map, head), SelectionGoal::None)
10908            });
10909        })
10910    }
10911
10912    pub fn select_to_next_word_end(
10913        &mut self,
10914        _: &SelectToNextWordEnd,
10915        window: &mut Window,
10916        cx: &mut Context<Self>,
10917    ) {
10918        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10919        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10920            s.move_heads_with(|map, head, _| {
10921                (movement::next_word_end(map, head), SelectionGoal::None)
10922            });
10923        })
10924    }
10925
10926    pub fn select_to_next_subword_end(
10927        &mut self,
10928        _: &SelectToNextSubwordEnd,
10929        window: &mut Window,
10930        cx: &mut Context<Self>,
10931    ) {
10932        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10934            s.move_heads_with(|map, head, _| {
10935                (movement::next_subword_end(map, head), SelectionGoal::None)
10936            });
10937        })
10938    }
10939
10940    pub fn delete_to_next_word_end(
10941        &mut self,
10942        action: &DeleteToNextWordEnd,
10943        window: &mut Window,
10944        cx: &mut Context<Self>,
10945    ) {
10946        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10947        self.transact(window, cx, |this, window, cx| {
10948            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10949                s.move_with(|map, selection| {
10950                    if selection.is_empty() {
10951                        let cursor = if action.ignore_newlines {
10952                            movement::next_word_end(map, selection.head())
10953                        } else {
10954                            movement::next_word_end_or_newline(map, selection.head())
10955                        };
10956                        selection.set_head(cursor, SelectionGoal::None);
10957                    }
10958                });
10959            });
10960            this.insert("", window, cx);
10961        });
10962    }
10963
10964    pub fn delete_to_next_subword_end(
10965        &mut self,
10966        _: &DeleteToNextSubwordEnd,
10967        window: &mut Window,
10968        cx: &mut Context<Self>,
10969    ) {
10970        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10971        self.transact(window, cx, |this, window, cx| {
10972            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10973                s.move_with(|map, selection| {
10974                    if selection.is_empty() {
10975                        let cursor = movement::next_subword_end(map, selection.head());
10976                        selection.set_head(cursor, SelectionGoal::None);
10977                    }
10978                });
10979            });
10980            this.insert("", window, cx);
10981        });
10982    }
10983
10984    pub fn move_to_beginning_of_line(
10985        &mut self,
10986        action: &MoveToBeginningOfLine,
10987        window: &mut Window,
10988        cx: &mut Context<Self>,
10989    ) {
10990        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10991        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10992            s.move_cursors_with(|map, head, _| {
10993                (
10994                    movement::indented_line_beginning(
10995                        map,
10996                        head,
10997                        action.stop_at_soft_wraps,
10998                        action.stop_at_indent,
10999                    ),
11000                    SelectionGoal::None,
11001                )
11002            });
11003        })
11004    }
11005
11006    pub fn select_to_beginning_of_line(
11007        &mut self,
11008        action: &SelectToBeginningOfLine,
11009        window: &mut Window,
11010        cx: &mut Context<Self>,
11011    ) {
11012        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11013        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11014            s.move_heads_with(|map, head, _| {
11015                (
11016                    movement::indented_line_beginning(
11017                        map,
11018                        head,
11019                        action.stop_at_soft_wraps,
11020                        action.stop_at_indent,
11021                    ),
11022                    SelectionGoal::None,
11023                )
11024            });
11025        });
11026    }
11027
11028    pub fn delete_to_beginning_of_line(
11029        &mut self,
11030        action: &DeleteToBeginningOfLine,
11031        window: &mut Window,
11032        cx: &mut Context<Self>,
11033    ) {
11034        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11035        self.transact(window, cx, |this, window, cx| {
11036            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11037                s.move_with(|_, selection| {
11038                    selection.reversed = true;
11039                });
11040            });
11041
11042            this.select_to_beginning_of_line(
11043                &SelectToBeginningOfLine {
11044                    stop_at_soft_wraps: false,
11045                    stop_at_indent: action.stop_at_indent,
11046                },
11047                window,
11048                cx,
11049            );
11050            this.backspace(&Backspace, window, cx);
11051        });
11052    }
11053
11054    pub fn move_to_end_of_line(
11055        &mut self,
11056        action: &MoveToEndOfLine,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11061        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11062            s.move_cursors_with(|map, head, _| {
11063                (
11064                    movement::line_end(map, head, action.stop_at_soft_wraps),
11065                    SelectionGoal::None,
11066                )
11067            });
11068        })
11069    }
11070
11071    pub fn select_to_end_of_line(
11072        &mut self,
11073        action: &SelectToEndOfLine,
11074        window: &mut Window,
11075        cx: &mut Context<Self>,
11076    ) {
11077        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11078        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11079            s.move_heads_with(|map, head, _| {
11080                (
11081                    movement::line_end(map, head, action.stop_at_soft_wraps),
11082                    SelectionGoal::None,
11083                )
11084            });
11085        })
11086    }
11087
11088    pub fn delete_to_end_of_line(
11089        &mut self,
11090        _: &DeleteToEndOfLine,
11091        window: &mut Window,
11092        cx: &mut Context<Self>,
11093    ) {
11094        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11095        self.transact(window, cx, |this, window, cx| {
11096            this.select_to_end_of_line(
11097                &SelectToEndOfLine {
11098                    stop_at_soft_wraps: false,
11099                },
11100                window,
11101                cx,
11102            );
11103            this.delete(&Delete, window, cx);
11104        });
11105    }
11106
11107    pub fn cut_to_end_of_line(
11108        &mut self,
11109        _: &CutToEndOfLine,
11110        window: &mut Window,
11111        cx: &mut Context<Self>,
11112    ) {
11113        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11114        self.transact(window, cx, |this, window, cx| {
11115            this.select_to_end_of_line(
11116                &SelectToEndOfLine {
11117                    stop_at_soft_wraps: false,
11118                },
11119                window,
11120                cx,
11121            );
11122            this.cut(&Cut, window, cx);
11123        });
11124    }
11125
11126    pub fn move_to_start_of_paragraph(
11127        &mut self,
11128        _: &MoveToStartOfParagraph,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11133            cx.propagate();
11134            return;
11135        }
11136        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11137        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11138            s.move_with(|map, selection| {
11139                selection.collapse_to(
11140                    movement::start_of_paragraph(map, selection.head(), 1),
11141                    SelectionGoal::None,
11142                )
11143            });
11144        })
11145    }
11146
11147    pub fn move_to_end_of_paragraph(
11148        &mut self,
11149        _: &MoveToEndOfParagraph,
11150        window: &mut Window,
11151        cx: &mut Context<Self>,
11152    ) {
11153        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11154            cx.propagate();
11155            return;
11156        }
11157        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11158        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11159            s.move_with(|map, selection| {
11160                selection.collapse_to(
11161                    movement::end_of_paragraph(map, selection.head(), 1),
11162                    SelectionGoal::None,
11163                )
11164            });
11165        })
11166    }
11167
11168    pub fn select_to_start_of_paragraph(
11169        &mut self,
11170        _: &SelectToStartOfParagraph,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11175            cx.propagate();
11176            return;
11177        }
11178        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11179        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11180            s.move_heads_with(|map, head, _| {
11181                (
11182                    movement::start_of_paragraph(map, head, 1),
11183                    SelectionGoal::None,
11184                )
11185            });
11186        })
11187    }
11188
11189    pub fn select_to_end_of_paragraph(
11190        &mut self,
11191        _: &SelectToEndOfParagraph,
11192        window: &mut Window,
11193        cx: &mut Context<Self>,
11194    ) {
11195        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11196            cx.propagate();
11197            return;
11198        }
11199        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11201            s.move_heads_with(|map, head, _| {
11202                (
11203                    movement::end_of_paragraph(map, head, 1),
11204                    SelectionGoal::None,
11205                )
11206            });
11207        })
11208    }
11209
11210    pub fn move_to_start_of_excerpt(
11211        &mut self,
11212        _: &MoveToStartOfExcerpt,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11217            cx.propagate();
11218            return;
11219        }
11220        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11221        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11222            s.move_with(|map, selection| {
11223                selection.collapse_to(
11224                    movement::start_of_excerpt(
11225                        map,
11226                        selection.head(),
11227                        workspace::searchable::Direction::Prev,
11228                    ),
11229                    SelectionGoal::None,
11230                )
11231            });
11232        })
11233    }
11234
11235    pub fn move_to_start_of_next_excerpt(
11236        &mut self,
11237        _: &MoveToStartOfNextExcerpt,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11242            cx.propagate();
11243            return;
11244        }
11245
11246        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11247            s.move_with(|map, selection| {
11248                selection.collapse_to(
11249                    movement::start_of_excerpt(
11250                        map,
11251                        selection.head(),
11252                        workspace::searchable::Direction::Next,
11253                    ),
11254                    SelectionGoal::None,
11255                )
11256            });
11257        })
11258    }
11259
11260    pub fn move_to_end_of_excerpt(
11261        &mut self,
11262        _: &MoveToEndOfExcerpt,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11267            cx.propagate();
11268            return;
11269        }
11270        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11271        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11272            s.move_with(|map, selection| {
11273                selection.collapse_to(
11274                    movement::end_of_excerpt(
11275                        map,
11276                        selection.head(),
11277                        workspace::searchable::Direction::Next,
11278                    ),
11279                    SelectionGoal::None,
11280                )
11281            });
11282        })
11283    }
11284
11285    pub fn move_to_end_of_previous_excerpt(
11286        &mut self,
11287        _: &MoveToEndOfPreviousExcerpt,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11292            cx.propagate();
11293            return;
11294        }
11295        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11296        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11297            s.move_with(|map, selection| {
11298                selection.collapse_to(
11299                    movement::end_of_excerpt(
11300                        map,
11301                        selection.head(),
11302                        workspace::searchable::Direction::Prev,
11303                    ),
11304                    SelectionGoal::None,
11305                )
11306            });
11307        })
11308    }
11309
11310    pub fn select_to_start_of_excerpt(
11311        &mut self,
11312        _: &SelectToStartOfExcerpt,
11313        window: &mut Window,
11314        cx: &mut Context<Self>,
11315    ) {
11316        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11317            cx.propagate();
11318            return;
11319        }
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11321        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11322            s.move_heads_with(|map, head, _| {
11323                (
11324                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11325                    SelectionGoal::None,
11326                )
11327            });
11328        })
11329    }
11330
11331    pub fn select_to_start_of_next_excerpt(
11332        &mut self,
11333        _: &SelectToStartOfNextExcerpt,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11338            cx.propagate();
11339            return;
11340        }
11341        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11342        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11343            s.move_heads_with(|map, head, _| {
11344                (
11345                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
11346                    SelectionGoal::None,
11347                )
11348            });
11349        })
11350    }
11351
11352    pub fn select_to_end_of_excerpt(
11353        &mut self,
11354        _: &SelectToEndOfExcerpt,
11355        window: &mut Window,
11356        cx: &mut Context<Self>,
11357    ) {
11358        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11359            cx.propagate();
11360            return;
11361        }
11362        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11363        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11364            s.move_heads_with(|map, head, _| {
11365                (
11366                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
11367                    SelectionGoal::None,
11368                )
11369            });
11370        })
11371    }
11372
11373    pub fn select_to_end_of_previous_excerpt(
11374        &mut self,
11375        _: &SelectToEndOfPreviousExcerpt,
11376        window: &mut Window,
11377        cx: &mut Context<Self>,
11378    ) {
11379        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11380            cx.propagate();
11381            return;
11382        }
11383        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11384        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11385            s.move_heads_with(|map, head, _| {
11386                (
11387                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11388                    SelectionGoal::None,
11389                )
11390            });
11391        })
11392    }
11393
11394    pub fn move_to_beginning(
11395        &mut self,
11396        _: &MoveToBeginning,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11401            cx.propagate();
11402            return;
11403        }
11404        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11405        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11406            s.select_ranges(vec![0..0]);
11407        });
11408    }
11409
11410    pub fn select_to_beginning(
11411        &mut self,
11412        _: &SelectToBeginning,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        let mut selection = self.selections.last::<Point>(cx);
11417        selection.set_head(Point::zero(), SelectionGoal::None);
11418        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11419        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11420            s.select(vec![selection]);
11421        });
11422    }
11423
11424    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
11425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11426            cx.propagate();
11427            return;
11428        }
11429        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11430        let cursor = self.buffer.read(cx).read(cx).len();
11431        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11432            s.select_ranges(vec![cursor..cursor])
11433        });
11434    }
11435
11436    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
11437        self.nav_history = nav_history;
11438    }
11439
11440    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
11441        self.nav_history.as_ref()
11442    }
11443
11444    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
11445        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
11446    }
11447
11448    fn push_to_nav_history(
11449        &mut self,
11450        cursor_anchor: Anchor,
11451        new_position: Option<Point>,
11452        is_deactivate: bool,
11453        cx: &mut Context<Self>,
11454    ) {
11455        if let Some(nav_history) = self.nav_history.as_mut() {
11456            let buffer = self.buffer.read(cx).read(cx);
11457            let cursor_position = cursor_anchor.to_point(&buffer);
11458            let scroll_state = self.scroll_manager.anchor();
11459            let scroll_top_row = scroll_state.top_row(&buffer);
11460            drop(buffer);
11461
11462            if let Some(new_position) = new_position {
11463                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
11464                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
11465                    return;
11466                }
11467            }
11468
11469            nav_history.push(
11470                Some(NavigationData {
11471                    cursor_anchor,
11472                    cursor_position,
11473                    scroll_anchor: scroll_state,
11474                    scroll_top_row,
11475                }),
11476                cx,
11477            );
11478            cx.emit(EditorEvent::PushedToNavHistory {
11479                anchor: cursor_anchor,
11480                is_deactivate,
11481            })
11482        }
11483    }
11484
11485    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
11486        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11487        let buffer = self.buffer.read(cx).snapshot(cx);
11488        let mut selection = self.selections.first::<usize>(cx);
11489        selection.set_head(buffer.len(), SelectionGoal::None);
11490        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11491            s.select(vec![selection]);
11492        });
11493    }
11494
11495    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
11496        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11497        let end = self.buffer.read(cx).read(cx).len();
11498        self.change_selections(None, window, cx, |s| {
11499            s.select_ranges(vec![0..end]);
11500        });
11501    }
11502
11503    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
11504        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11506        let mut selections = self.selections.all::<Point>(cx);
11507        let max_point = display_map.buffer_snapshot.max_point();
11508        for selection in &mut selections {
11509            let rows = selection.spanned_rows(true, &display_map);
11510            selection.start = Point::new(rows.start.0, 0);
11511            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
11512            selection.reversed = false;
11513        }
11514        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11515            s.select(selections);
11516        });
11517    }
11518
11519    pub fn split_selection_into_lines(
11520        &mut self,
11521        _: &SplitSelectionIntoLines,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        let selections = self
11526            .selections
11527            .all::<Point>(cx)
11528            .into_iter()
11529            .map(|selection| selection.start..selection.end)
11530            .collect::<Vec<_>>();
11531        self.unfold_ranges(&selections, true, true, cx);
11532
11533        let mut new_selection_ranges = Vec::new();
11534        {
11535            let buffer = self.buffer.read(cx).read(cx);
11536            for selection in selections {
11537                for row in selection.start.row..selection.end.row {
11538                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11539                    new_selection_ranges.push(cursor..cursor);
11540                }
11541
11542                let is_multiline_selection = selection.start.row != selection.end.row;
11543                // Don't insert last one if it's a multi-line selection ending at the start of a line,
11544                // so this action feels more ergonomic when paired with other selection operations
11545                let should_skip_last = is_multiline_selection && selection.end.column == 0;
11546                if !should_skip_last {
11547                    new_selection_ranges.push(selection.end..selection.end);
11548                }
11549            }
11550        }
11551        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11552            s.select_ranges(new_selection_ranges);
11553        });
11554    }
11555
11556    pub fn add_selection_above(
11557        &mut self,
11558        _: &AddSelectionAbove,
11559        window: &mut Window,
11560        cx: &mut Context<Self>,
11561    ) {
11562        self.add_selection(true, window, cx);
11563    }
11564
11565    pub fn add_selection_below(
11566        &mut self,
11567        _: &AddSelectionBelow,
11568        window: &mut Window,
11569        cx: &mut Context<Self>,
11570    ) {
11571        self.add_selection(false, window, cx);
11572    }
11573
11574    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
11575        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11576
11577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11578        let mut selections = self.selections.all::<Point>(cx);
11579        let text_layout_details = self.text_layout_details(window);
11580        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
11581            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
11582            let range = oldest_selection.display_range(&display_map).sorted();
11583
11584            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
11585            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
11586            let positions = start_x.min(end_x)..start_x.max(end_x);
11587
11588            selections.clear();
11589            let mut stack = Vec::new();
11590            for row in range.start.row().0..=range.end.row().0 {
11591                if let Some(selection) = self.selections.build_columnar_selection(
11592                    &display_map,
11593                    DisplayRow(row),
11594                    &positions,
11595                    oldest_selection.reversed,
11596                    &text_layout_details,
11597                ) {
11598                    stack.push(selection.id);
11599                    selections.push(selection);
11600                }
11601            }
11602
11603            if above {
11604                stack.reverse();
11605            }
11606
11607            AddSelectionsState { above, stack }
11608        });
11609
11610        let last_added_selection = *state.stack.last().unwrap();
11611        let mut new_selections = Vec::new();
11612        if above == state.above {
11613            let end_row = if above {
11614                DisplayRow(0)
11615            } else {
11616                display_map.max_point().row()
11617            };
11618
11619            'outer: for selection in selections {
11620                if selection.id == last_added_selection {
11621                    let range = selection.display_range(&display_map).sorted();
11622                    debug_assert_eq!(range.start.row(), range.end.row());
11623                    let mut row = range.start.row();
11624                    let positions =
11625                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
11626                            px(start)..px(end)
11627                        } else {
11628                            let start_x =
11629                                display_map.x_for_display_point(range.start, &text_layout_details);
11630                            let end_x =
11631                                display_map.x_for_display_point(range.end, &text_layout_details);
11632                            start_x.min(end_x)..start_x.max(end_x)
11633                        };
11634
11635                    while row != end_row {
11636                        if above {
11637                            row.0 -= 1;
11638                        } else {
11639                            row.0 += 1;
11640                        }
11641
11642                        if let Some(new_selection) = self.selections.build_columnar_selection(
11643                            &display_map,
11644                            row,
11645                            &positions,
11646                            selection.reversed,
11647                            &text_layout_details,
11648                        ) {
11649                            state.stack.push(new_selection.id);
11650                            if above {
11651                                new_selections.push(new_selection);
11652                                new_selections.push(selection);
11653                            } else {
11654                                new_selections.push(selection);
11655                                new_selections.push(new_selection);
11656                            }
11657
11658                            continue 'outer;
11659                        }
11660                    }
11661                }
11662
11663                new_selections.push(selection);
11664            }
11665        } else {
11666            new_selections = selections;
11667            new_selections.retain(|s| s.id != last_added_selection);
11668            state.stack.pop();
11669        }
11670
11671        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11672            s.select(new_selections);
11673        });
11674        if state.stack.len() > 1 {
11675            self.add_selections_state = Some(state);
11676        }
11677    }
11678
11679    pub fn select_next_match_internal(
11680        &mut self,
11681        display_map: &DisplaySnapshot,
11682        replace_newest: bool,
11683        autoscroll: Option<Autoscroll>,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) -> Result<()> {
11687        fn select_next_match_ranges(
11688            this: &mut Editor,
11689            range: Range<usize>,
11690            replace_newest: bool,
11691            auto_scroll: Option<Autoscroll>,
11692            window: &mut Window,
11693            cx: &mut Context<Editor>,
11694        ) {
11695            this.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
11696            this.change_selections(auto_scroll, window, cx, |s| {
11697                if replace_newest {
11698                    s.delete(s.newest_anchor().id);
11699                }
11700                s.insert_range(range.clone());
11701            });
11702        }
11703
11704        let buffer = &display_map.buffer_snapshot;
11705        let mut selections = self.selections.all::<usize>(cx);
11706        if let Some(mut select_next_state) = self.select_next_state.take() {
11707            let query = &select_next_state.query;
11708            if !select_next_state.done {
11709                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
11710                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
11711                let mut next_selected_range = None;
11712
11713                let bytes_after_last_selection =
11714                    buffer.bytes_in_range(last_selection.end..buffer.len());
11715                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
11716                let query_matches = query
11717                    .stream_find_iter(bytes_after_last_selection)
11718                    .map(|result| (last_selection.end, result))
11719                    .chain(
11720                        query
11721                            .stream_find_iter(bytes_before_first_selection)
11722                            .map(|result| (0, result)),
11723                    );
11724
11725                for (start_offset, query_match) in query_matches {
11726                    let query_match = query_match.unwrap(); // can only fail due to I/O
11727                    let offset_range =
11728                        start_offset + query_match.start()..start_offset + query_match.end();
11729                    let display_range = offset_range.start.to_display_point(display_map)
11730                        ..offset_range.end.to_display_point(display_map);
11731
11732                    if !select_next_state.wordwise
11733                        || (!movement::is_inside_word(display_map, display_range.start)
11734                            && !movement::is_inside_word(display_map, display_range.end))
11735                    {
11736                        // TODO: This is n^2, because we might check all the selections
11737                        if !selections
11738                            .iter()
11739                            .any(|selection| selection.range().overlaps(&offset_range))
11740                        {
11741                            next_selected_range = Some(offset_range);
11742                            break;
11743                        }
11744                    }
11745                }
11746
11747                if let Some(next_selected_range) = next_selected_range {
11748                    select_next_match_ranges(
11749                        self,
11750                        next_selected_range,
11751                        replace_newest,
11752                        autoscroll,
11753                        window,
11754                        cx,
11755                    );
11756                } else {
11757                    select_next_state.done = true;
11758                }
11759            }
11760
11761            self.select_next_state = Some(select_next_state);
11762        } else {
11763            let mut only_carets = true;
11764            let mut same_text_selected = true;
11765            let mut selected_text = None;
11766
11767            let mut selections_iter = selections.iter().peekable();
11768            while let Some(selection) = selections_iter.next() {
11769                if selection.start != selection.end {
11770                    only_carets = false;
11771                }
11772
11773                if same_text_selected {
11774                    if selected_text.is_none() {
11775                        selected_text =
11776                            Some(buffer.text_for_range(selection.range()).collect::<String>());
11777                    }
11778
11779                    if let Some(next_selection) = selections_iter.peek() {
11780                        if next_selection.range().len() == selection.range().len() {
11781                            let next_selected_text = buffer
11782                                .text_for_range(next_selection.range())
11783                                .collect::<String>();
11784                            if Some(next_selected_text) != selected_text {
11785                                same_text_selected = false;
11786                                selected_text = None;
11787                            }
11788                        } else {
11789                            same_text_selected = false;
11790                            selected_text = None;
11791                        }
11792                    }
11793                }
11794            }
11795
11796            if only_carets {
11797                for selection in &mut selections {
11798                    let word_range = movement::surrounding_word(
11799                        display_map,
11800                        selection.start.to_display_point(display_map),
11801                    );
11802                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
11803                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
11804                    selection.goal = SelectionGoal::None;
11805                    selection.reversed = false;
11806                    select_next_match_ranges(
11807                        self,
11808                        selection.start..selection.end,
11809                        replace_newest,
11810                        autoscroll,
11811                        window,
11812                        cx,
11813                    );
11814                }
11815
11816                if selections.len() == 1 {
11817                    let selection = selections
11818                        .last()
11819                        .expect("ensured that there's only one selection");
11820                    let query = buffer
11821                        .text_for_range(selection.start..selection.end)
11822                        .collect::<String>();
11823                    let is_empty = query.is_empty();
11824                    let select_state = SelectNextState {
11825                        query: AhoCorasick::new(&[query])?,
11826                        wordwise: true,
11827                        done: is_empty,
11828                    };
11829                    self.select_next_state = Some(select_state);
11830                } else {
11831                    self.select_next_state = None;
11832                }
11833            } else if let Some(selected_text) = selected_text {
11834                self.select_next_state = Some(SelectNextState {
11835                    query: AhoCorasick::new(&[selected_text])?,
11836                    wordwise: false,
11837                    done: false,
11838                });
11839                self.select_next_match_internal(
11840                    display_map,
11841                    replace_newest,
11842                    autoscroll,
11843                    window,
11844                    cx,
11845                )?;
11846            }
11847        }
11848        Ok(())
11849    }
11850
11851    pub fn select_all_matches(
11852        &mut self,
11853        _action: &SelectAllMatches,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) -> Result<()> {
11857        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11858
11859        self.push_to_selection_history();
11860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11861
11862        self.select_next_match_internal(&display_map, false, None, window, cx)?;
11863        let Some(select_next_state) = self.select_next_state.as_mut() else {
11864            return Ok(());
11865        };
11866        if select_next_state.done {
11867            return Ok(());
11868        }
11869
11870        let mut new_selections = Vec::new();
11871
11872        let reversed = self.selections.oldest::<usize>(cx).reversed;
11873        let buffer = &display_map.buffer_snapshot;
11874        let query_matches = select_next_state
11875            .query
11876            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
11877
11878        for query_match in query_matches.into_iter() {
11879            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
11880            let offset_range = if reversed {
11881                query_match.end()..query_match.start()
11882            } else {
11883                query_match.start()..query_match.end()
11884            };
11885            let display_range = offset_range.start.to_display_point(&display_map)
11886                ..offset_range.end.to_display_point(&display_map);
11887
11888            if !select_next_state.wordwise
11889                || (!movement::is_inside_word(&display_map, display_range.start)
11890                    && !movement::is_inside_word(&display_map, display_range.end))
11891            {
11892                new_selections.push(offset_range.start..offset_range.end);
11893            }
11894        }
11895
11896        select_next_state.done = true;
11897        self.unfold_ranges(&new_selections.clone(), false, false, cx);
11898        self.change_selections(None, window, cx, |selections| {
11899            selections.select_ranges(new_selections)
11900        });
11901
11902        Ok(())
11903    }
11904
11905    pub fn select_next(
11906        &mut self,
11907        action: &SelectNext,
11908        window: &mut Window,
11909        cx: &mut Context<Self>,
11910    ) -> Result<()> {
11911        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11912        self.push_to_selection_history();
11913        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11914        self.select_next_match_internal(
11915            &display_map,
11916            action.replace_newest,
11917            Some(Autoscroll::newest()),
11918            window,
11919            cx,
11920        )?;
11921        Ok(())
11922    }
11923
11924    pub fn select_previous(
11925        &mut self,
11926        action: &SelectPrevious,
11927        window: &mut Window,
11928        cx: &mut Context<Self>,
11929    ) -> Result<()> {
11930        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11931        self.push_to_selection_history();
11932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11933        let buffer = &display_map.buffer_snapshot;
11934        let mut selections = self.selections.all::<usize>(cx);
11935        if let Some(mut select_prev_state) = self.select_prev_state.take() {
11936            let query = &select_prev_state.query;
11937            if !select_prev_state.done {
11938                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
11939                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
11940                let mut next_selected_range = None;
11941                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
11942                let bytes_before_last_selection =
11943                    buffer.reversed_bytes_in_range(0..last_selection.start);
11944                let bytes_after_first_selection =
11945                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
11946                let query_matches = query
11947                    .stream_find_iter(bytes_before_last_selection)
11948                    .map(|result| (last_selection.start, result))
11949                    .chain(
11950                        query
11951                            .stream_find_iter(bytes_after_first_selection)
11952                            .map(|result| (buffer.len(), result)),
11953                    );
11954                for (end_offset, query_match) in query_matches {
11955                    let query_match = query_match.unwrap(); // can only fail due to I/O
11956                    let offset_range =
11957                        end_offset - query_match.end()..end_offset - query_match.start();
11958                    let display_range = offset_range.start.to_display_point(&display_map)
11959                        ..offset_range.end.to_display_point(&display_map);
11960
11961                    if !select_prev_state.wordwise
11962                        || (!movement::is_inside_word(&display_map, display_range.start)
11963                            && !movement::is_inside_word(&display_map, display_range.end))
11964                    {
11965                        next_selected_range = Some(offset_range);
11966                        break;
11967                    }
11968                }
11969
11970                if let Some(next_selected_range) = next_selected_range {
11971                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
11972                    self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
11973                        if action.replace_newest {
11974                            s.delete(s.newest_anchor().id);
11975                        }
11976                        s.insert_range(next_selected_range);
11977                    });
11978                } else {
11979                    select_prev_state.done = true;
11980                }
11981            }
11982
11983            self.select_prev_state = Some(select_prev_state);
11984        } else {
11985            let mut only_carets = true;
11986            let mut same_text_selected = true;
11987            let mut selected_text = None;
11988
11989            let mut selections_iter = selections.iter().peekable();
11990            while let Some(selection) = selections_iter.next() {
11991                if selection.start != selection.end {
11992                    only_carets = false;
11993                }
11994
11995                if same_text_selected {
11996                    if selected_text.is_none() {
11997                        selected_text =
11998                            Some(buffer.text_for_range(selection.range()).collect::<String>());
11999                    }
12000
12001                    if let Some(next_selection) = selections_iter.peek() {
12002                        if next_selection.range().len() == selection.range().len() {
12003                            let next_selected_text = buffer
12004                                .text_for_range(next_selection.range())
12005                                .collect::<String>();
12006                            if Some(next_selected_text) != selected_text {
12007                                same_text_selected = false;
12008                                selected_text = None;
12009                            }
12010                        } else {
12011                            same_text_selected = false;
12012                            selected_text = None;
12013                        }
12014                    }
12015                }
12016            }
12017
12018            if only_carets {
12019                for selection in &mut selections {
12020                    let word_range = movement::surrounding_word(
12021                        &display_map,
12022                        selection.start.to_display_point(&display_map),
12023                    );
12024                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12025                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12026                    selection.goal = SelectionGoal::None;
12027                    selection.reversed = false;
12028                }
12029                if selections.len() == 1 {
12030                    let selection = selections
12031                        .last()
12032                        .expect("ensured that there's only one selection");
12033                    let query = buffer
12034                        .text_for_range(selection.start..selection.end)
12035                        .collect::<String>();
12036                    let is_empty = query.is_empty();
12037                    let select_state = SelectNextState {
12038                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12039                        wordwise: true,
12040                        done: is_empty,
12041                    };
12042                    self.select_prev_state = Some(select_state);
12043                } else {
12044                    self.select_prev_state = None;
12045                }
12046
12047                self.unfold_ranges(
12048                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
12049                    false,
12050                    true,
12051                    cx,
12052                );
12053                self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12054                    s.select(selections);
12055                });
12056            } else if let Some(selected_text) = selected_text {
12057                self.select_prev_state = Some(SelectNextState {
12058                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12059                    wordwise: false,
12060                    done: false,
12061                });
12062                self.select_previous(action, window, cx)?;
12063            }
12064        }
12065        Ok(())
12066    }
12067
12068    pub fn find_next_match(
12069        &mut self,
12070        _: &FindNextMatch,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) -> Result<()> {
12074        let selections = self.selections.disjoint_anchors();
12075        match selections.first() {
12076            Some(first) if selections.len() >= 2 => {
12077                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078                    s.select_ranges([first.range()]);
12079                });
12080            }
12081            _ => self.select_next(
12082                &SelectNext {
12083                    replace_newest: true,
12084                },
12085                window,
12086                cx,
12087            )?,
12088        }
12089        Ok(())
12090    }
12091
12092    pub fn find_previous_match(
12093        &mut self,
12094        _: &FindPreviousMatch,
12095        window: &mut Window,
12096        cx: &mut Context<Self>,
12097    ) -> Result<()> {
12098        let selections = self.selections.disjoint_anchors();
12099        match selections.last() {
12100            Some(last) if selections.len() >= 2 => {
12101                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12102                    s.select_ranges([last.range()]);
12103                });
12104            }
12105            _ => self.select_previous(
12106                &SelectPrevious {
12107                    replace_newest: true,
12108                },
12109                window,
12110                cx,
12111            )?,
12112        }
12113        Ok(())
12114    }
12115
12116    pub fn toggle_comments(
12117        &mut self,
12118        action: &ToggleComments,
12119        window: &mut Window,
12120        cx: &mut Context<Self>,
12121    ) {
12122        if self.read_only(cx) {
12123            return;
12124        }
12125        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12126        let text_layout_details = &self.text_layout_details(window);
12127        self.transact(window, cx, |this, window, cx| {
12128            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12129            let mut edits = Vec::new();
12130            let mut selection_edit_ranges = Vec::new();
12131            let mut last_toggled_row = None;
12132            let snapshot = this.buffer.read(cx).read(cx);
12133            let empty_str: Arc<str> = Arc::default();
12134            let mut suffixes_inserted = Vec::new();
12135            let ignore_indent = action.ignore_indent;
12136
12137            fn comment_prefix_range(
12138                snapshot: &MultiBufferSnapshot,
12139                row: MultiBufferRow,
12140                comment_prefix: &str,
12141                comment_prefix_whitespace: &str,
12142                ignore_indent: bool,
12143            ) -> Range<Point> {
12144                let indent_size = if ignore_indent {
12145                    0
12146                } else {
12147                    snapshot.indent_size_for_line(row).len
12148                };
12149
12150                let start = Point::new(row.0, indent_size);
12151
12152                let mut line_bytes = snapshot
12153                    .bytes_in_range(start..snapshot.max_point())
12154                    .flatten()
12155                    .copied();
12156
12157                // If this line currently begins with the line comment prefix, then record
12158                // the range containing the prefix.
12159                if line_bytes
12160                    .by_ref()
12161                    .take(comment_prefix.len())
12162                    .eq(comment_prefix.bytes())
12163                {
12164                    // Include any whitespace that matches the comment prefix.
12165                    let matching_whitespace_len = line_bytes
12166                        .zip(comment_prefix_whitespace.bytes())
12167                        .take_while(|(a, b)| a == b)
12168                        .count() as u32;
12169                    let end = Point::new(
12170                        start.row,
12171                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12172                    );
12173                    start..end
12174                } else {
12175                    start..start
12176                }
12177            }
12178
12179            fn comment_suffix_range(
12180                snapshot: &MultiBufferSnapshot,
12181                row: MultiBufferRow,
12182                comment_suffix: &str,
12183                comment_suffix_has_leading_space: bool,
12184            ) -> Range<Point> {
12185                let end = Point::new(row.0, snapshot.line_len(row));
12186                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12187
12188                let mut line_end_bytes = snapshot
12189                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12190                    .flatten()
12191                    .copied();
12192
12193                let leading_space_len = if suffix_start_column > 0
12194                    && line_end_bytes.next() == Some(b' ')
12195                    && comment_suffix_has_leading_space
12196                {
12197                    1
12198                } else {
12199                    0
12200                };
12201
12202                // If this line currently begins with the line comment prefix, then record
12203                // the range containing the prefix.
12204                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12205                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12206                    start..end
12207                } else {
12208                    end..end
12209                }
12210            }
12211
12212            // TODO: Handle selections that cross excerpts
12213            for selection in &mut selections {
12214                let start_column = snapshot
12215                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12216                    .len;
12217                let language = if let Some(language) =
12218                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12219                {
12220                    language
12221                } else {
12222                    continue;
12223                };
12224
12225                selection_edit_ranges.clear();
12226
12227                // If multiple selections contain a given row, avoid processing that
12228                // row more than once.
12229                let mut start_row = MultiBufferRow(selection.start.row);
12230                if last_toggled_row == Some(start_row) {
12231                    start_row = start_row.next_row();
12232                }
12233                let end_row =
12234                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12235                        MultiBufferRow(selection.end.row - 1)
12236                    } else {
12237                        MultiBufferRow(selection.end.row)
12238                    };
12239                last_toggled_row = Some(end_row);
12240
12241                if start_row > end_row {
12242                    continue;
12243                }
12244
12245                // If the language has line comments, toggle those.
12246                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12247
12248                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12249                if ignore_indent {
12250                    full_comment_prefixes = full_comment_prefixes
12251                        .into_iter()
12252                        .map(|s| Arc::from(s.trim_end()))
12253                        .collect();
12254                }
12255
12256                if !full_comment_prefixes.is_empty() {
12257                    let first_prefix = full_comment_prefixes
12258                        .first()
12259                        .expect("prefixes is non-empty");
12260                    let prefix_trimmed_lengths = full_comment_prefixes
12261                        .iter()
12262                        .map(|p| p.trim_end_matches(' ').len())
12263                        .collect::<SmallVec<[usize; 4]>>();
12264
12265                    let mut all_selection_lines_are_comments = true;
12266
12267                    for row in start_row.0..=end_row.0 {
12268                        let row = MultiBufferRow(row);
12269                        if start_row < end_row && snapshot.is_line_blank(row) {
12270                            continue;
12271                        }
12272
12273                        let prefix_range = full_comment_prefixes
12274                            .iter()
12275                            .zip(prefix_trimmed_lengths.iter().copied())
12276                            .map(|(prefix, trimmed_prefix_len)| {
12277                                comment_prefix_range(
12278                                    snapshot.deref(),
12279                                    row,
12280                                    &prefix[..trimmed_prefix_len],
12281                                    &prefix[trimmed_prefix_len..],
12282                                    ignore_indent,
12283                                )
12284                            })
12285                            .max_by_key(|range| range.end.column - range.start.column)
12286                            .expect("prefixes is non-empty");
12287
12288                        if prefix_range.is_empty() {
12289                            all_selection_lines_are_comments = false;
12290                        }
12291
12292                        selection_edit_ranges.push(prefix_range);
12293                    }
12294
12295                    if all_selection_lines_are_comments {
12296                        edits.extend(
12297                            selection_edit_ranges
12298                                .iter()
12299                                .cloned()
12300                                .map(|range| (range, empty_str.clone())),
12301                        );
12302                    } else {
12303                        let min_column = selection_edit_ranges
12304                            .iter()
12305                            .map(|range| range.start.column)
12306                            .min()
12307                            .unwrap_or(0);
12308                        edits.extend(selection_edit_ranges.iter().map(|range| {
12309                            let position = Point::new(range.start.row, min_column);
12310                            (position..position, first_prefix.clone())
12311                        }));
12312                    }
12313                } else if let Some((full_comment_prefix, comment_suffix)) =
12314                    language.block_comment_delimiters()
12315                {
12316                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
12317                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
12318                    let prefix_range = comment_prefix_range(
12319                        snapshot.deref(),
12320                        start_row,
12321                        comment_prefix,
12322                        comment_prefix_whitespace,
12323                        ignore_indent,
12324                    );
12325                    let suffix_range = comment_suffix_range(
12326                        snapshot.deref(),
12327                        end_row,
12328                        comment_suffix.trim_start_matches(' '),
12329                        comment_suffix.starts_with(' '),
12330                    );
12331
12332                    if prefix_range.is_empty() || suffix_range.is_empty() {
12333                        edits.push((
12334                            prefix_range.start..prefix_range.start,
12335                            full_comment_prefix.clone(),
12336                        ));
12337                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
12338                        suffixes_inserted.push((end_row, comment_suffix.len()));
12339                    } else {
12340                        edits.push((prefix_range, empty_str.clone()));
12341                        edits.push((suffix_range, empty_str.clone()));
12342                    }
12343                } else {
12344                    continue;
12345                }
12346            }
12347
12348            drop(snapshot);
12349            this.buffer.update(cx, |buffer, cx| {
12350                buffer.edit(edits, None, cx);
12351            });
12352
12353            // Adjust selections so that they end before any comment suffixes that
12354            // were inserted.
12355            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
12356            let mut selections = this.selections.all::<Point>(cx);
12357            let snapshot = this.buffer.read(cx).read(cx);
12358            for selection in &mut selections {
12359                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
12360                    match row.cmp(&MultiBufferRow(selection.end.row)) {
12361                        Ordering::Less => {
12362                            suffixes_inserted.next();
12363                            continue;
12364                        }
12365                        Ordering::Greater => break,
12366                        Ordering::Equal => {
12367                            if selection.end.column == snapshot.line_len(row) {
12368                                if selection.is_empty() {
12369                                    selection.start.column -= suffix_len as u32;
12370                                }
12371                                selection.end.column -= suffix_len as u32;
12372                            }
12373                            break;
12374                        }
12375                    }
12376                }
12377            }
12378
12379            drop(snapshot);
12380            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12381                s.select(selections)
12382            });
12383
12384            let selections = this.selections.all::<Point>(cx);
12385            let selections_on_single_row = selections.windows(2).all(|selections| {
12386                selections[0].start.row == selections[1].start.row
12387                    && selections[0].end.row == selections[1].end.row
12388                    && selections[0].start.row == selections[0].end.row
12389            });
12390            let selections_selecting = selections
12391                .iter()
12392                .any(|selection| selection.start != selection.end);
12393            let advance_downwards = action.advance_downwards
12394                && selections_on_single_row
12395                && !selections_selecting
12396                && !matches!(this.mode, EditorMode::SingleLine { .. });
12397
12398            if advance_downwards {
12399                let snapshot = this.buffer.read(cx).snapshot(cx);
12400
12401                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12402                    s.move_cursors_with(|display_snapshot, display_point, _| {
12403                        let mut point = display_point.to_point(display_snapshot);
12404                        point.row += 1;
12405                        point = snapshot.clip_point(point, Bias::Left);
12406                        let display_point = point.to_display_point(display_snapshot);
12407                        let goal = SelectionGoal::HorizontalPosition(
12408                            display_snapshot
12409                                .x_for_display_point(display_point, text_layout_details)
12410                                .into(),
12411                        );
12412                        (display_point, goal)
12413                    })
12414                });
12415            }
12416        });
12417    }
12418
12419    pub fn select_enclosing_symbol(
12420        &mut self,
12421        _: &SelectEnclosingSymbol,
12422        window: &mut Window,
12423        cx: &mut Context<Self>,
12424    ) {
12425        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12426
12427        let buffer = self.buffer.read(cx).snapshot(cx);
12428        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
12429
12430        fn update_selection(
12431            selection: &Selection<usize>,
12432            buffer_snap: &MultiBufferSnapshot,
12433        ) -> Option<Selection<usize>> {
12434            let cursor = selection.head();
12435            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
12436            for symbol in symbols.iter().rev() {
12437                let start = symbol.range.start.to_offset(buffer_snap);
12438                let end = symbol.range.end.to_offset(buffer_snap);
12439                let new_range = start..end;
12440                if start < selection.start || end > selection.end {
12441                    return Some(Selection {
12442                        id: selection.id,
12443                        start: new_range.start,
12444                        end: new_range.end,
12445                        goal: SelectionGoal::None,
12446                        reversed: selection.reversed,
12447                    });
12448                }
12449            }
12450            None
12451        }
12452
12453        let mut selected_larger_symbol = false;
12454        let new_selections = old_selections
12455            .iter()
12456            .map(|selection| match update_selection(selection, &buffer) {
12457                Some(new_selection) => {
12458                    if new_selection.range() != selection.range() {
12459                        selected_larger_symbol = true;
12460                    }
12461                    new_selection
12462                }
12463                None => selection.clone(),
12464            })
12465            .collect::<Vec<_>>();
12466
12467        if selected_larger_symbol {
12468            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12469                s.select(new_selections);
12470            });
12471        }
12472    }
12473
12474    pub fn select_larger_syntax_node(
12475        &mut self,
12476        _: &SelectLargerSyntaxNode,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        let Some(visible_row_count) = self.visible_row_count() else {
12481            return;
12482        };
12483        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
12484        if old_selections.is_empty() {
12485            return;
12486        }
12487
12488        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12489
12490        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12491        let buffer = self.buffer.read(cx).snapshot(cx);
12492
12493        let mut selected_larger_node = false;
12494        let mut new_selections = old_selections
12495            .iter()
12496            .map(|selection| {
12497                let old_range = selection.start..selection.end;
12498                let mut new_range = old_range.clone();
12499                let mut new_node = None;
12500                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
12501                {
12502                    new_node = Some(node);
12503                    new_range = match containing_range {
12504                        MultiOrSingleBufferOffsetRange::Single(_) => break,
12505                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
12506                    };
12507                    if !display_map.intersects_fold(new_range.start)
12508                        && !display_map.intersects_fold(new_range.end)
12509                    {
12510                        break;
12511                    }
12512                }
12513
12514                if let Some(node) = new_node {
12515                    // Log the ancestor, to support using this action as a way to explore TreeSitter
12516                    // nodes. Parent and grandparent are also logged because this operation will not
12517                    // visit nodes that have the same range as their parent.
12518                    log::info!("Node: {node:?}");
12519                    let parent = node.parent();
12520                    log::info!("Parent: {parent:?}");
12521                    let grandparent = parent.and_then(|x| x.parent());
12522                    log::info!("Grandparent: {grandparent:?}");
12523                }
12524
12525                selected_larger_node |= new_range != old_range;
12526                Selection {
12527                    id: selection.id,
12528                    start: new_range.start,
12529                    end: new_range.end,
12530                    goal: SelectionGoal::None,
12531                    reversed: selection.reversed,
12532                }
12533            })
12534            .collect::<Vec<_>>();
12535
12536        if !selected_larger_node {
12537            return; // don't put this call in the history
12538        }
12539
12540        // scroll based on transformation done to the last selection created by the user
12541        let (last_old, last_new) = old_selections
12542            .last()
12543            .zip(new_selections.last().cloned())
12544            .expect("old_selections isn't empty");
12545
12546        // revert selection
12547        let is_selection_reversed = {
12548            let should_newest_selection_be_reversed = last_old.start != last_new.start;
12549            new_selections.last_mut().expect("checked above").reversed =
12550                should_newest_selection_be_reversed;
12551            should_newest_selection_be_reversed
12552        };
12553
12554        if selected_larger_node {
12555            self.select_syntax_node_history.disable_clearing = true;
12556            self.change_selections(None, window, cx, |s| {
12557                s.select(new_selections.clone());
12558            });
12559            self.select_syntax_node_history.disable_clearing = false;
12560        }
12561
12562        let start_row = last_new.start.to_display_point(&display_map).row().0;
12563        let end_row = last_new.end.to_display_point(&display_map).row().0;
12564        let selection_height = end_row - start_row + 1;
12565        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
12566
12567        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
12568        let scroll_behavior = if fits_on_the_screen {
12569            self.request_autoscroll(Autoscroll::fit(), cx);
12570            SelectSyntaxNodeScrollBehavior::FitSelection
12571        } else if is_selection_reversed {
12572            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12573            SelectSyntaxNodeScrollBehavior::CursorTop
12574        } else {
12575            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12576            SelectSyntaxNodeScrollBehavior::CursorBottom
12577        };
12578
12579        self.select_syntax_node_history.push((
12580            old_selections,
12581            scroll_behavior,
12582            is_selection_reversed,
12583        ));
12584    }
12585
12586    pub fn select_smaller_syntax_node(
12587        &mut self,
12588        _: &SelectSmallerSyntaxNode,
12589        window: &mut Window,
12590        cx: &mut Context<Self>,
12591    ) {
12592        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12593
12594        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
12595            self.select_syntax_node_history.pop()
12596        {
12597            if let Some(selection) = selections.last_mut() {
12598                selection.reversed = is_selection_reversed;
12599            }
12600
12601            self.select_syntax_node_history.disable_clearing = true;
12602            self.change_selections(None, window, cx, |s| {
12603                s.select(selections.to_vec());
12604            });
12605            self.select_syntax_node_history.disable_clearing = false;
12606
12607            match scroll_behavior {
12608                SelectSyntaxNodeScrollBehavior::CursorTop => {
12609                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12610                }
12611                SelectSyntaxNodeScrollBehavior::FitSelection => {
12612                    self.request_autoscroll(Autoscroll::fit(), cx);
12613                }
12614                SelectSyntaxNodeScrollBehavior::CursorBottom => {
12615                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12616                }
12617            }
12618        }
12619    }
12620
12621    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
12622        if !EditorSettings::get_global(cx).gutter.runnables {
12623            self.clear_tasks();
12624            return Task::ready(());
12625        }
12626        let project = self.project.as_ref().map(Entity::downgrade);
12627        let task_sources = self.lsp_task_sources(cx);
12628        cx.spawn_in(window, async move |editor, cx| {
12629            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
12630            let Some(project) = project.and_then(|p| p.upgrade()) else {
12631                return;
12632            };
12633            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
12634                this.display_map.update(cx, |map, cx| map.snapshot(cx))
12635            }) else {
12636                return;
12637            };
12638
12639            let hide_runnables = project
12640                .update(cx, |project, cx| {
12641                    // Do not display any test indicators in non-dev server remote projects.
12642                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
12643                })
12644                .unwrap_or(true);
12645            if hide_runnables {
12646                return;
12647            }
12648            let new_rows =
12649                cx.background_spawn({
12650                    let snapshot = display_snapshot.clone();
12651                    async move {
12652                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
12653                    }
12654                })
12655                    .await;
12656            let Ok(lsp_tasks) =
12657                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
12658            else {
12659                return;
12660            };
12661            let lsp_tasks = lsp_tasks.await;
12662
12663            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
12664                lsp_tasks
12665                    .into_iter()
12666                    .flat_map(|(kind, tasks)| {
12667                        tasks.into_iter().filter_map(move |(location, task)| {
12668                            Some((kind.clone(), location?, task))
12669                        })
12670                    })
12671                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
12672                        let buffer = location.target.buffer;
12673                        let buffer_snapshot = buffer.read(cx).snapshot();
12674                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
12675                            |(excerpt_id, snapshot, _)| {
12676                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
12677                                    display_snapshot
12678                                        .buffer_snapshot
12679                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
12680                                } else {
12681                                    None
12682                                }
12683                            },
12684                        );
12685                        if let Some(offset) = offset {
12686                            let task_buffer_range =
12687                                location.target.range.to_point(&buffer_snapshot);
12688                            let context_buffer_range =
12689                                task_buffer_range.to_offset(&buffer_snapshot);
12690                            let context_range = BufferOffset(context_buffer_range.start)
12691                                ..BufferOffset(context_buffer_range.end);
12692
12693                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
12694                                .or_insert_with(|| RunnableTasks {
12695                                    templates: Vec::new(),
12696                                    offset,
12697                                    column: task_buffer_range.start.column,
12698                                    extra_variables: HashMap::default(),
12699                                    context_range,
12700                                })
12701                                .templates
12702                                .push((kind, task.original_task().clone()));
12703                        }
12704
12705                        acc
12706                    })
12707            }) else {
12708                return;
12709            };
12710
12711            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
12712            editor
12713                .update(cx, |editor, _| {
12714                    editor.clear_tasks();
12715                    for (key, mut value) in rows {
12716                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
12717                            value.templates.extend(lsp_tasks.templates);
12718                        }
12719
12720                        editor.insert_tasks(key, value);
12721                    }
12722                    for (key, value) in lsp_tasks_by_rows {
12723                        editor.insert_tasks(key, value);
12724                    }
12725                })
12726                .ok();
12727        })
12728    }
12729    fn fetch_runnable_ranges(
12730        snapshot: &DisplaySnapshot,
12731        range: Range<Anchor>,
12732    ) -> Vec<language::RunnableRange> {
12733        snapshot.buffer_snapshot.runnable_ranges(range).collect()
12734    }
12735
12736    fn runnable_rows(
12737        project: Entity<Project>,
12738        snapshot: DisplaySnapshot,
12739        runnable_ranges: Vec<RunnableRange>,
12740        mut cx: AsyncWindowContext,
12741    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
12742        runnable_ranges
12743            .into_iter()
12744            .filter_map(|mut runnable| {
12745                let tasks = cx
12746                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
12747                    .ok()?;
12748                if tasks.is_empty() {
12749                    return None;
12750                }
12751
12752                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
12753
12754                let row = snapshot
12755                    .buffer_snapshot
12756                    .buffer_line_for_row(MultiBufferRow(point.row))?
12757                    .1
12758                    .start
12759                    .row;
12760
12761                let context_range =
12762                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
12763                Some((
12764                    (runnable.buffer_id, row),
12765                    RunnableTasks {
12766                        templates: tasks,
12767                        offset: snapshot
12768                            .buffer_snapshot
12769                            .anchor_before(runnable.run_range.start),
12770                        context_range,
12771                        column: point.column,
12772                        extra_variables: runnable.extra_captures,
12773                    },
12774                ))
12775            })
12776            .collect()
12777    }
12778
12779    fn templates_with_tags(
12780        project: &Entity<Project>,
12781        runnable: &mut Runnable,
12782        cx: &mut App,
12783    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
12784        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
12785            let (worktree_id, file) = project
12786                .buffer_for_id(runnable.buffer, cx)
12787                .and_then(|buffer| buffer.read(cx).file())
12788                .map(|file| (file.worktree_id(cx), file.clone()))
12789                .unzip();
12790
12791            (
12792                project.task_store().read(cx).task_inventory().cloned(),
12793                worktree_id,
12794                file,
12795            )
12796        });
12797
12798        let mut templates_with_tags = mem::take(&mut runnable.tags)
12799            .into_iter()
12800            .flat_map(|RunnableTag(tag)| {
12801                inventory
12802                    .as_ref()
12803                    .into_iter()
12804                    .flat_map(|inventory| {
12805                        inventory.read(cx).list_tasks(
12806                            file.clone(),
12807                            Some(runnable.language.clone()),
12808                            worktree_id,
12809                            cx,
12810                        )
12811                    })
12812                    .filter(move |(_, template)| {
12813                        template.tags.iter().any(|source_tag| source_tag == &tag)
12814                    })
12815            })
12816            .sorted_by_key(|(kind, _)| kind.to_owned())
12817            .collect::<Vec<_>>();
12818        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
12819            // Strongest source wins; if we have worktree tag binding, prefer that to
12820            // global and language bindings;
12821            // if we have a global binding, prefer that to language binding.
12822            let first_mismatch = templates_with_tags
12823                .iter()
12824                .position(|(tag_source, _)| tag_source != leading_tag_source);
12825            if let Some(index) = first_mismatch {
12826                templates_with_tags.truncate(index);
12827            }
12828        }
12829
12830        templates_with_tags
12831    }
12832
12833    pub fn move_to_enclosing_bracket(
12834        &mut self,
12835        _: &MoveToEnclosingBracket,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12840        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12841            s.move_offsets_with(|snapshot, selection| {
12842                let Some(enclosing_bracket_ranges) =
12843                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
12844                else {
12845                    return;
12846                };
12847
12848                let mut best_length = usize::MAX;
12849                let mut best_inside = false;
12850                let mut best_in_bracket_range = false;
12851                let mut best_destination = None;
12852                for (open, close) in enclosing_bracket_ranges {
12853                    let close = close.to_inclusive();
12854                    let length = close.end() - open.start;
12855                    let inside = selection.start >= open.end && selection.end <= *close.start();
12856                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
12857                        || close.contains(&selection.head());
12858
12859                    // If best is next to a bracket and current isn't, skip
12860                    if !in_bracket_range && best_in_bracket_range {
12861                        continue;
12862                    }
12863
12864                    // Prefer smaller lengths unless best is inside and current isn't
12865                    if length > best_length && (best_inside || !inside) {
12866                        continue;
12867                    }
12868
12869                    best_length = length;
12870                    best_inside = inside;
12871                    best_in_bracket_range = in_bracket_range;
12872                    best_destination = Some(
12873                        if close.contains(&selection.start) && close.contains(&selection.end) {
12874                            if inside { open.end } else { open.start }
12875                        } else if inside {
12876                            *close.start()
12877                        } else {
12878                            *close.end()
12879                        },
12880                    );
12881                }
12882
12883                if let Some(destination) = best_destination {
12884                    selection.collapse_to(destination, SelectionGoal::None);
12885                }
12886            })
12887        });
12888    }
12889
12890    pub fn undo_selection(
12891        &mut self,
12892        _: &UndoSelection,
12893        window: &mut Window,
12894        cx: &mut Context<Self>,
12895    ) {
12896        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12897        self.end_selection(window, cx);
12898        self.selection_history.mode = SelectionHistoryMode::Undoing;
12899        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
12900            self.change_selections(None, window, cx, |s| {
12901                s.select_anchors(entry.selections.to_vec())
12902            });
12903            self.select_next_state = entry.select_next_state;
12904            self.select_prev_state = entry.select_prev_state;
12905            self.add_selections_state = entry.add_selections_state;
12906            self.request_autoscroll(Autoscroll::newest(), cx);
12907        }
12908        self.selection_history.mode = SelectionHistoryMode::Normal;
12909    }
12910
12911    pub fn redo_selection(
12912        &mut self,
12913        _: &RedoSelection,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12918        self.end_selection(window, cx);
12919        self.selection_history.mode = SelectionHistoryMode::Redoing;
12920        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
12921            self.change_selections(None, window, cx, |s| {
12922                s.select_anchors(entry.selections.to_vec())
12923            });
12924            self.select_next_state = entry.select_next_state;
12925            self.select_prev_state = entry.select_prev_state;
12926            self.add_selections_state = entry.add_selections_state;
12927            self.request_autoscroll(Autoscroll::newest(), cx);
12928        }
12929        self.selection_history.mode = SelectionHistoryMode::Normal;
12930    }
12931
12932    pub fn expand_excerpts(
12933        &mut self,
12934        action: &ExpandExcerpts,
12935        _: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
12939    }
12940
12941    pub fn expand_excerpts_down(
12942        &mut self,
12943        action: &ExpandExcerptsDown,
12944        _: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
12948    }
12949
12950    pub fn expand_excerpts_up(
12951        &mut self,
12952        action: &ExpandExcerptsUp,
12953        _: &mut Window,
12954        cx: &mut Context<Self>,
12955    ) {
12956        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
12957    }
12958
12959    pub fn expand_excerpts_for_direction(
12960        &mut self,
12961        lines: u32,
12962        direction: ExpandExcerptDirection,
12963
12964        cx: &mut Context<Self>,
12965    ) {
12966        let selections = self.selections.disjoint_anchors();
12967
12968        let lines = if lines == 0 {
12969            EditorSettings::get_global(cx).expand_excerpt_lines
12970        } else {
12971            lines
12972        };
12973
12974        self.buffer.update(cx, |buffer, cx| {
12975            let snapshot = buffer.snapshot(cx);
12976            let mut excerpt_ids = selections
12977                .iter()
12978                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
12979                .collect::<Vec<_>>();
12980            excerpt_ids.sort();
12981            excerpt_ids.dedup();
12982            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
12983        })
12984    }
12985
12986    pub fn expand_excerpt(
12987        &mut self,
12988        excerpt: ExcerptId,
12989        direction: ExpandExcerptDirection,
12990        window: &mut Window,
12991        cx: &mut Context<Self>,
12992    ) {
12993        let current_scroll_position = self.scroll_position(cx);
12994        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
12995        let mut should_scroll_up = false;
12996
12997        if direction == ExpandExcerptDirection::Down {
12998            let multi_buffer = self.buffer.read(cx);
12999            let snapshot = multi_buffer.snapshot(cx);
13000            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13001                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13002                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13003                        let buffer_snapshot = buffer.read(cx).snapshot();
13004                        let excerpt_end_row =
13005                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13006                        let last_row = buffer_snapshot.max_point().row;
13007                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13008                        should_scroll_up = lines_below >= lines_to_expand;
13009                    }
13010                }
13011            }
13012        }
13013
13014        self.buffer.update(cx, |buffer, cx| {
13015            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13016        });
13017
13018        if should_scroll_up {
13019            let new_scroll_position =
13020                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13021            self.set_scroll_position(new_scroll_position, window, cx);
13022        }
13023    }
13024
13025    pub fn go_to_singleton_buffer_point(
13026        &mut self,
13027        point: Point,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        self.go_to_singleton_buffer_range(point..point, window, cx);
13032    }
13033
13034    pub fn go_to_singleton_buffer_range(
13035        &mut self,
13036        range: Range<Point>,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        let multibuffer = self.buffer().read(cx);
13041        let Some(buffer) = multibuffer.as_singleton() else {
13042            return;
13043        };
13044        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13045            return;
13046        };
13047        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13048            return;
13049        };
13050        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13051            s.select_anchor_ranges([start..end])
13052        });
13053    }
13054
13055    fn go_to_diagnostic(
13056        &mut self,
13057        _: &GoToDiagnostic,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13062        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13063    }
13064
13065    fn go_to_prev_diagnostic(
13066        &mut self,
13067        _: &GoToPreviousDiagnostic,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13072        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13073    }
13074
13075    pub fn go_to_diagnostic_impl(
13076        &mut self,
13077        direction: Direction,
13078        window: &mut Window,
13079        cx: &mut Context<Self>,
13080    ) {
13081        let buffer = self.buffer.read(cx).snapshot(cx);
13082        let selection = self.selections.newest::<usize>(cx);
13083        // If there is an active Diagnostic Popover jump to its diagnostic instead.
13084        if direction == Direction::Next {
13085            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
13086                let Some(buffer_id) = popover.local_diagnostic.range.start.buffer_id else {
13087                    return;
13088                };
13089                self.activate_diagnostics(
13090                    buffer_id,
13091                    popover.local_diagnostic.diagnostic.group_id,
13092                    window,
13093                    cx,
13094                );
13095                if let Some(active_diagnostics) = self.active_diagnostics.as_ref() {
13096                    let primary_range_start = active_diagnostics.primary_range.start;
13097                    self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13098                        let mut new_selection = s.newest_anchor().clone();
13099                        new_selection.collapse_to(primary_range_start, SelectionGoal::None);
13100                        s.select_anchors(vec![new_selection.clone()]);
13101                    });
13102                    self.refresh_inline_completion(false, true, window, cx);
13103                }
13104                return;
13105            }
13106        }
13107
13108        let active_group_id = self
13109            .active_diagnostics
13110            .as_ref()
13111            .map(|active_group| active_group.group_id);
13112        let active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
13113            active_diagnostics
13114                .primary_range
13115                .to_offset(&buffer)
13116                .to_inclusive()
13117        });
13118        let search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
13119            if active_primary_range.contains(&selection.head()) {
13120                *active_primary_range.start()
13121            } else {
13122                selection.head()
13123            }
13124        } else {
13125            selection.head()
13126        };
13127
13128        let snapshot = self.snapshot(window, cx);
13129        let primary_diagnostics_before = buffer
13130            .diagnostics_in_range::<usize>(0..search_start)
13131            .filter(|entry| entry.diagnostic.is_primary)
13132            .filter(|entry| entry.range.start != entry.range.end)
13133            .filter(|entry| entry.diagnostic.severity <= DiagnosticSeverity::WARNING)
13134            .filter(|entry| !snapshot.intersects_fold(entry.range.start))
13135            .collect::<Vec<_>>();
13136        let last_same_group_diagnostic_before = active_group_id.and_then(|active_group_id| {
13137            primary_diagnostics_before
13138                .iter()
13139                .position(|entry| entry.diagnostic.group_id == active_group_id)
13140        });
13141
13142        let primary_diagnostics_after = buffer
13143            .diagnostics_in_range::<usize>(search_start..buffer.len())
13144            .filter(|entry| entry.diagnostic.is_primary)
13145            .filter(|entry| entry.range.start != entry.range.end)
13146            .filter(|entry| entry.diagnostic.severity <= DiagnosticSeverity::WARNING)
13147            .filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start))
13148            .collect::<Vec<_>>();
13149        let last_same_group_diagnostic_after = active_group_id.and_then(|active_group_id| {
13150            primary_diagnostics_after
13151                .iter()
13152                .enumerate()
13153                .rev()
13154                .find_map(|(i, entry)| {
13155                    if entry.diagnostic.group_id == active_group_id {
13156                        Some(i)
13157                    } else {
13158                        None
13159                    }
13160                })
13161        });
13162
13163        let next_primary_diagnostic = match direction {
13164            Direction::Prev => primary_diagnostics_before
13165                .iter()
13166                .take(last_same_group_diagnostic_before.unwrap_or(usize::MAX))
13167                .rev()
13168                .next(),
13169            Direction::Next => primary_diagnostics_after
13170                .iter()
13171                .skip(
13172                    last_same_group_diagnostic_after
13173                        .map(|index| index + 1)
13174                        .unwrap_or(0),
13175                )
13176                .next(),
13177        };
13178
13179        // Cycle around to the start of the buffer, potentially moving back to the start of
13180        // the currently active diagnostic.
13181        let cycle_around = || match direction {
13182            Direction::Prev => primary_diagnostics_after
13183                .iter()
13184                .rev()
13185                .chain(primary_diagnostics_before.iter().rev())
13186                .next(),
13187            Direction::Next => primary_diagnostics_before
13188                .iter()
13189                .chain(primary_diagnostics_after.iter())
13190                .next(),
13191        };
13192
13193        if let Some((primary_range, group_id)) = next_primary_diagnostic
13194            .or_else(cycle_around)
13195            .map(|entry| (&entry.range, entry.diagnostic.group_id))
13196        {
13197            let Some(buffer_id) = buffer.anchor_after(primary_range.start).buffer_id else {
13198                return;
13199            };
13200            self.activate_diagnostics(buffer_id, group_id, window, cx);
13201            if self.active_diagnostics.is_some() {
13202                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13203                    s.select(vec![Selection {
13204                        id: selection.id,
13205                        start: primary_range.start,
13206                        end: primary_range.start,
13207                        reversed: false,
13208                        goal: SelectionGoal::None,
13209                    }]);
13210                });
13211                self.refresh_inline_completion(false, true, window, cx);
13212            }
13213        }
13214    }
13215
13216    fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13217        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13218        let snapshot = self.snapshot(window, cx);
13219        let selection = self.selections.newest::<Point>(cx);
13220        self.go_to_hunk_before_or_after_position(
13221            &snapshot,
13222            selection.head(),
13223            Direction::Next,
13224            window,
13225            cx,
13226        );
13227    }
13228
13229    pub fn go_to_hunk_before_or_after_position(
13230        &mut self,
13231        snapshot: &EditorSnapshot,
13232        position: Point,
13233        direction: Direction,
13234        window: &mut Window,
13235        cx: &mut Context<Editor>,
13236    ) {
13237        let row = if direction == Direction::Next {
13238            self.hunk_after_position(snapshot, position)
13239                .map(|hunk| hunk.row_range.start)
13240        } else {
13241            self.hunk_before_position(snapshot, position)
13242        };
13243
13244        if let Some(row) = row {
13245            let destination = Point::new(row.0, 0);
13246            let autoscroll = Autoscroll::center();
13247
13248            self.unfold_ranges(&[destination..destination], false, false, cx);
13249            self.change_selections(Some(autoscroll), window, cx, |s| {
13250                s.select_ranges([destination..destination]);
13251            });
13252        }
13253    }
13254
13255    fn hunk_after_position(
13256        &mut self,
13257        snapshot: &EditorSnapshot,
13258        position: Point,
13259    ) -> Option<MultiBufferDiffHunk> {
13260        snapshot
13261            .buffer_snapshot
13262            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13263            .find(|hunk| hunk.row_range.start.0 > position.row)
13264            .or_else(|| {
13265                snapshot
13266                    .buffer_snapshot
13267                    .diff_hunks_in_range(Point::zero()..position)
13268                    .find(|hunk| hunk.row_range.end.0 < position.row)
13269            })
13270    }
13271
13272    fn go_to_prev_hunk(
13273        &mut self,
13274        _: &GoToPreviousHunk,
13275        window: &mut Window,
13276        cx: &mut Context<Self>,
13277    ) {
13278        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13279        let snapshot = self.snapshot(window, cx);
13280        let selection = self.selections.newest::<Point>(cx);
13281        self.go_to_hunk_before_or_after_position(
13282            &snapshot,
13283            selection.head(),
13284            Direction::Prev,
13285            window,
13286            cx,
13287        );
13288    }
13289
13290    fn hunk_before_position(
13291        &mut self,
13292        snapshot: &EditorSnapshot,
13293        position: Point,
13294    ) -> Option<MultiBufferRow> {
13295        snapshot
13296            .buffer_snapshot
13297            .diff_hunk_before(position)
13298            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13299    }
13300
13301    fn go_to_line<T: 'static>(
13302        &mut self,
13303        position: Anchor,
13304        highlight_color: Option<Hsla>,
13305        window: &mut Window,
13306        cx: &mut Context<Self>,
13307    ) {
13308        let snapshot = self.snapshot(window, cx).display_snapshot;
13309        let position = position.to_point(&snapshot.buffer_snapshot);
13310        let start = snapshot
13311            .buffer_snapshot
13312            .clip_point(Point::new(position.row, 0), Bias::Left);
13313        let end = start + Point::new(1, 0);
13314        let start = snapshot.buffer_snapshot.anchor_before(start);
13315        let end = snapshot.buffer_snapshot.anchor_before(end);
13316
13317        self.highlight_rows::<T>(
13318            start..end,
13319            highlight_color
13320                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
13321            false,
13322            cx,
13323        );
13324        self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
13325    }
13326
13327    pub fn go_to_definition(
13328        &mut self,
13329        _: &GoToDefinition,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) -> Task<Result<Navigated>> {
13333        let definition =
13334            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
13335        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
13336        cx.spawn_in(window, async move |editor, cx| {
13337            if definition.await? == Navigated::Yes {
13338                return Ok(Navigated::Yes);
13339            }
13340            match fallback_strategy {
13341                GoToDefinitionFallback::None => Ok(Navigated::No),
13342                GoToDefinitionFallback::FindAllReferences => {
13343                    match editor.update_in(cx, |editor, window, cx| {
13344                        editor.find_all_references(&FindAllReferences, window, cx)
13345                    })? {
13346                        Some(references) => references.await,
13347                        None => Ok(Navigated::No),
13348                    }
13349                }
13350            }
13351        })
13352    }
13353
13354    pub fn go_to_declaration(
13355        &mut self,
13356        _: &GoToDeclaration,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) -> Task<Result<Navigated>> {
13360        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
13361    }
13362
13363    pub fn go_to_declaration_split(
13364        &mut self,
13365        _: &GoToDeclaration,
13366        window: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) -> Task<Result<Navigated>> {
13369        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
13370    }
13371
13372    pub fn go_to_implementation(
13373        &mut self,
13374        _: &GoToImplementation,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) -> Task<Result<Navigated>> {
13378        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
13379    }
13380
13381    pub fn go_to_implementation_split(
13382        &mut self,
13383        _: &GoToImplementationSplit,
13384        window: &mut Window,
13385        cx: &mut Context<Self>,
13386    ) -> Task<Result<Navigated>> {
13387        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
13388    }
13389
13390    pub fn go_to_type_definition(
13391        &mut self,
13392        _: &GoToTypeDefinition,
13393        window: &mut Window,
13394        cx: &mut Context<Self>,
13395    ) -> Task<Result<Navigated>> {
13396        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
13397    }
13398
13399    pub fn go_to_definition_split(
13400        &mut self,
13401        _: &GoToDefinitionSplit,
13402        window: &mut Window,
13403        cx: &mut Context<Self>,
13404    ) -> Task<Result<Navigated>> {
13405        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
13406    }
13407
13408    pub fn go_to_type_definition_split(
13409        &mut self,
13410        _: &GoToTypeDefinitionSplit,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) -> Task<Result<Navigated>> {
13414        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
13415    }
13416
13417    fn go_to_definition_of_kind(
13418        &mut self,
13419        kind: GotoDefinitionKind,
13420        split: bool,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) -> Task<Result<Navigated>> {
13424        let Some(provider) = self.semantics_provider.clone() else {
13425            return Task::ready(Ok(Navigated::No));
13426        };
13427        let head = self.selections.newest::<usize>(cx).head();
13428        let buffer = self.buffer.read(cx);
13429        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
13430            text_anchor
13431        } else {
13432            return Task::ready(Ok(Navigated::No));
13433        };
13434
13435        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
13436            return Task::ready(Ok(Navigated::No));
13437        };
13438
13439        cx.spawn_in(window, async move |editor, cx| {
13440            let definitions = definitions.await?;
13441            let navigated = editor
13442                .update_in(cx, |editor, window, cx| {
13443                    editor.navigate_to_hover_links(
13444                        Some(kind),
13445                        definitions
13446                            .into_iter()
13447                            .filter(|location| {
13448                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
13449                            })
13450                            .map(HoverLink::Text)
13451                            .collect::<Vec<_>>(),
13452                        split,
13453                        window,
13454                        cx,
13455                    )
13456                })?
13457                .await?;
13458            anyhow::Ok(navigated)
13459        })
13460    }
13461
13462    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
13463        let selection = self.selections.newest_anchor();
13464        let head = selection.head();
13465        let tail = selection.tail();
13466
13467        let Some((buffer, start_position)) =
13468            self.buffer.read(cx).text_anchor_for_position(head, cx)
13469        else {
13470            return;
13471        };
13472
13473        let end_position = if head != tail {
13474            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
13475                return;
13476            };
13477            Some(pos)
13478        } else {
13479            None
13480        };
13481
13482        let url_finder = cx.spawn_in(window, async move |editor, cx| {
13483            let url = if let Some(end_pos) = end_position {
13484                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
13485            } else {
13486                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
13487            };
13488
13489            if let Some(url) = url {
13490                editor.update(cx, |_, cx| {
13491                    cx.open_url(&url);
13492                })
13493            } else {
13494                Ok(())
13495            }
13496        });
13497
13498        url_finder.detach();
13499    }
13500
13501    pub fn open_selected_filename(
13502        &mut self,
13503        _: &OpenSelectedFilename,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        let Some(workspace) = self.workspace() else {
13508            return;
13509        };
13510
13511        let position = self.selections.newest_anchor().head();
13512
13513        let Some((buffer, buffer_position)) =
13514            self.buffer.read(cx).text_anchor_for_position(position, cx)
13515        else {
13516            return;
13517        };
13518
13519        let project = self.project.clone();
13520
13521        cx.spawn_in(window, async move |_, cx| {
13522            let result = find_file(&buffer, project, buffer_position, cx).await;
13523
13524            if let Some((_, path)) = result {
13525                workspace
13526                    .update_in(cx, |workspace, window, cx| {
13527                        workspace.open_resolved_path(path, window, cx)
13528                    })?
13529                    .await?;
13530            }
13531            anyhow::Ok(())
13532        })
13533        .detach();
13534    }
13535
13536    pub(crate) fn navigate_to_hover_links(
13537        &mut self,
13538        kind: Option<GotoDefinitionKind>,
13539        mut definitions: Vec<HoverLink>,
13540        split: bool,
13541        window: &mut Window,
13542        cx: &mut Context<Editor>,
13543    ) -> Task<Result<Navigated>> {
13544        // If there is one definition, just open it directly
13545        if definitions.len() == 1 {
13546            let definition = definitions.pop().unwrap();
13547
13548            enum TargetTaskResult {
13549                Location(Option<Location>),
13550                AlreadyNavigated,
13551            }
13552
13553            let target_task = match definition {
13554                HoverLink::Text(link) => {
13555                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
13556                }
13557                HoverLink::InlayHint(lsp_location, server_id) => {
13558                    let computation =
13559                        self.compute_target_location(lsp_location, server_id, window, cx);
13560                    cx.background_spawn(async move {
13561                        let location = computation.await?;
13562                        Ok(TargetTaskResult::Location(location))
13563                    })
13564                }
13565                HoverLink::Url(url) => {
13566                    cx.open_url(&url);
13567                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
13568                }
13569                HoverLink::File(path) => {
13570                    if let Some(workspace) = self.workspace() {
13571                        cx.spawn_in(window, async move |_, cx| {
13572                            workspace
13573                                .update_in(cx, |workspace, window, cx| {
13574                                    workspace.open_resolved_path(path, window, cx)
13575                                })?
13576                                .await
13577                                .map(|_| TargetTaskResult::AlreadyNavigated)
13578                        })
13579                    } else {
13580                        Task::ready(Ok(TargetTaskResult::Location(None)))
13581                    }
13582                }
13583            };
13584            cx.spawn_in(window, async move |editor, cx| {
13585                let target = match target_task.await.context("target resolution task")? {
13586                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
13587                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
13588                    TargetTaskResult::Location(Some(target)) => target,
13589                };
13590
13591                editor.update_in(cx, |editor, window, cx| {
13592                    let Some(workspace) = editor.workspace() else {
13593                        return Navigated::No;
13594                    };
13595                    let pane = workspace.read(cx).active_pane().clone();
13596
13597                    let range = target.range.to_point(target.buffer.read(cx));
13598                    let range = editor.range_for_match(&range);
13599                    let range = collapse_multiline_range(range);
13600
13601                    if !split
13602                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
13603                    {
13604                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
13605                    } else {
13606                        window.defer(cx, move |window, cx| {
13607                            let target_editor: Entity<Self> =
13608                                workspace.update(cx, |workspace, cx| {
13609                                    let pane = if split {
13610                                        workspace.adjacent_pane(window, cx)
13611                                    } else {
13612                                        workspace.active_pane().clone()
13613                                    };
13614
13615                                    workspace.open_project_item(
13616                                        pane,
13617                                        target.buffer.clone(),
13618                                        true,
13619                                        true,
13620                                        window,
13621                                        cx,
13622                                    )
13623                                });
13624                            target_editor.update(cx, |target_editor, cx| {
13625                                // When selecting a definition in a different buffer, disable the nav history
13626                                // to avoid creating a history entry at the previous cursor location.
13627                                pane.update(cx, |pane, _| pane.disable_history());
13628                                target_editor.go_to_singleton_buffer_range(range, window, cx);
13629                                pane.update(cx, |pane, _| pane.enable_history());
13630                            });
13631                        });
13632                    }
13633                    Navigated::Yes
13634                })
13635            })
13636        } else if !definitions.is_empty() {
13637            cx.spawn_in(window, async move |editor, cx| {
13638                let (title, location_tasks, workspace) = editor
13639                    .update_in(cx, |editor, window, cx| {
13640                        let tab_kind = match kind {
13641                            Some(GotoDefinitionKind::Implementation) => "Implementations",
13642                            _ => "Definitions",
13643                        };
13644                        let title = definitions
13645                            .iter()
13646                            .find_map(|definition| match definition {
13647                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
13648                                    let buffer = origin.buffer.read(cx);
13649                                    format!(
13650                                        "{} for {}",
13651                                        tab_kind,
13652                                        buffer
13653                                            .text_for_range(origin.range.clone())
13654                                            .collect::<String>()
13655                                    )
13656                                }),
13657                                HoverLink::InlayHint(_, _) => None,
13658                                HoverLink::Url(_) => None,
13659                                HoverLink::File(_) => None,
13660                            })
13661                            .unwrap_or(tab_kind.to_string());
13662                        let location_tasks = definitions
13663                            .into_iter()
13664                            .map(|definition| match definition {
13665                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
13666                                HoverLink::InlayHint(lsp_location, server_id) => editor
13667                                    .compute_target_location(lsp_location, server_id, window, cx),
13668                                HoverLink::Url(_) => Task::ready(Ok(None)),
13669                                HoverLink::File(_) => Task::ready(Ok(None)),
13670                            })
13671                            .collect::<Vec<_>>();
13672                        (title, location_tasks, editor.workspace().clone())
13673                    })
13674                    .context("location tasks preparation")?;
13675
13676                let locations = future::join_all(location_tasks)
13677                    .await
13678                    .into_iter()
13679                    .filter_map(|location| location.transpose())
13680                    .collect::<Result<_>>()
13681                    .context("location tasks")?;
13682
13683                let Some(workspace) = workspace else {
13684                    return Ok(Navigated::No);
13685                };
13686                let opened = workspace
13687                    .update_in(cx, |workspace, window, cx| {
13688                        Self::open_locations_in_multibuffer(
13689                            workspace,
13690                            locations,
13691                            title,
13692                            split,
13693                            MultibufferSelectionMode::First,
13694                            window,
13695                            cx,
13696                        )
13697                    })
13698                    .ok();
13699
13700                anyhow::Ok(Navigated::from_bool(opened.is_some()))
13701            })
13702        } else {
13703            Task::ready(Ok(Navigated::No))
13704        }
13705    }
13706
13707    fn compute_target_location(
13708        &self,
13709        lsp_location: lsp::Location,
13710        server_id: LanguageServerId,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) -> Task<anyhow::Result<Option<Location>>> {
13714        let Some(project) = self.project.clone() else {
13715            return Task::ready(Ok(None));
13716        };
13717
13718        cx.spawn_in(window, async move |editor, cx| {
13719            let location_task = editor.update(cx, |_, cx| {
13720                project.update(cx, |project, cx| {
13721                    let language_server_name = project
13722                        .language_server_statuses(cx)
13723                        .find(|(id, _)| server_id == *id)
13724                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
13725                    language_server_name.map(|language_server_name| {
13726                        project.open_local_buffer_via_lsp(
13727                            lsp_location.uri.clone(),
13728                            server_id,
13729                            language_server_name,
13730                            cx,
13731                        )
13732                    })
13733                })
13734            })?;
13735            let location = match location_task {
13736                Some(task) => Some({
13737                    let target_buffer_handle = task.await.context("open local buffer")?;
13738                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
13739                        let target_start = target_buffer
13740                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
13741                        let target_end = target_buffer
13742                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
13743                        target_buffer.anchor_after(target_start)
13744                            ..target_buffer.anchor_before(target_end)
13745                    })?;
13746                    Location {
13747                        buffer: target_buffer_handle,
13748                        range,
13749                    }
13750                }),
13751                None => None,
13752            };
13753            Ok(location)
13754        })
13755    }
13756
13757    pub fn find_all_references(
13758        &mut self,
13759        _: &FindAllReferences,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) -> Option<Task<Result<Navigated>>> {
13763        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13764
13765        let selection = self.selections.newest::<usize>(cx);
13766        let multi_buffer = self.buffer.read(cx);
13767        let head = selection.head();
13768
13769        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
13770        let head_anchor = multi_buffer_snapshot.anchor_at(
13771            head,
13772            if head < selection.tail() {
13773                Bias::Right
13774            } else {
13775                Bias::Left
13776            },
13777        );
13778
13779        match self
13780            .find_all_references_task_sources
13781            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
13782        {
13783            Ok(_) => {
13784                log::info!(
13785                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
13786                );
13787                return None;
13788            }
13789            Err(i) => {
13790                self.find_all_references_task_sources.insert(i, head_anchor);
13791            }
13792        }
13793
13794        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
13795        let workspace = self.workspace()?;
13796        let project = workspace.read(cx).project().clone();
13797        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
13798        Some(cx.spawn_in(window, async move |editor, cx| {
13799            let _cleanup = cx.on_drop(&editor, move |editor, _| {
13800                if let Ok(i) = editor
13801                    .find_all_references_task_sources
13802                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
13803                {
13804                    editor.find_all_references_task_sources.remove(i);
13805                }
13806            });
13807
13808            let locations = references.await?;
13809            if locations.is_empty() {
13810                return anyhow::Ok(Navigated::No);
13811            }
13812
13813            workspace.update_in(cx, |workspace, window, cx| {
13814                let title = locations
13815                    .first()
13816                    .as_ref()
13817                    .map(|location| {
13818                        let buffer = location.buffer.read(cx);
13819                        format!(
13820                            "References to `{}`",
13821                            buffer
13822                                .text_for_range(location.range.clone())
13823                                .collect::<String>()
13824                        )
13825                    })
13826                    .unwrap();
13827                Self::open_locations_in_multibuffer(
13828                    workspace,
13829                    locations,
13830                    title,
13831                    false,
13832                    MultibufferSelectionMode::First,
13833                    window,
13834                    cx,
13835                );
13836                Navigated::Yes
13837            })
13838        }))
13839    }
13840
13841    /// Opens a multibuffer with the given project locations in it
13842    pub fn open_locations_in_multibuffer(
13843        workspace: &mut Workspace,
13844        mut locations: Vec<Location>,
13845        title: String,
13846        split: bool,
13847        multibuffer_selection_mode: MultibufferSelectionMode,
13848        window: &mut Window,
13849        cx: &mut Context<Workspace>,
13850    ) {
13851        // If there are multiple definitions, open them in a multibuffer
13852        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
13853        let mut locations = locations.into_iter().peekable();
13854        let mut ranges: Vec<Range<Anchor>> = Vec::new();
13855        let capability = workspace.project().read(cx).capability();
13856
13857        let excerpt_buffer = cx.new(|cx| {
13858            let mut multibuffer = MultiBuffer::new(capability);
13859            while let Some(location) = locations.next() {
13860                let buffer = location.buffer.read(cx);
13861                let mut ranges_for_buffer = Vec::new();
13862                let range = location.range.to_point(buffer);
13863                ranges_for_buffer.push(range.clone());
13864
13865                while let Some(next_location) = locations.peek() {
13866                    if next_location.buffer == location.buffer {
13867                        ranges_for_buffer.push(next_location.range.to_point(buffer));
13868                        locations.next();
13869                    } else {
13870                        break;
13871                    }
13872                }
13873
13874                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
13875                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
13876                    PathKey::for_buffer(&location.buffer, cx),
13877                    location.buffer.clone(),
13878                    ranges_for_buffer,
13879                    DEFAULT_MULTIBUFFER_CONTEXT,
13880                    cx,
13881                );
13882                ranges.extend(new_ranges)
13883            }
13884
13885            multibuffer.with_title(title)
13886        });
13887
13888        let editor = cx.new(|cx| {
13889            Editor::for_multibuffer(
13890                excerpt_buffer,
13891                Some(workspace.project().clone()),
13892                window,
13893                cx,
13894            )
13895        });
13896        editor.update(cx, |editor, cx| {
13897            match multibuffer_selection_mode {
13898                MultibufferSelectionMode::First => {
13899                    if let Some(first_range) = ranges.first() {
13900                        editor.change_selections(None, window, cx, |selections| {
13901                            selections.clear_disjoint();
13902                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
13903                        });
13904                    }
13905                    editor.highlight_background::<Self>(
13906                        &ranges,
13907                        |theme| theme.editor_highlighted_line_background,
13908                        cx,
13909                    );
13910                }
13911                MultibufferSelectionMode::All => {
13912                    editor.change_selections(None, window, cx, |selections| {
13913                        selections.clear_disjoint();
13914                        selections.select_anchor_ranges(ranges);
13915                    });
13916                }
13917            }
13918            editor.register_buffers_with_language_servers(cx);
13919        });
13920
13921        let item = Box::new(editor);
13922        let item_id = item.item_id();
13923
13924        if split {
13925            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
13926        } else {
13927            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
13928                let (preview_item_id, preview_item_idx) =
13929                    workspace.active_pane().update(cx, |pane, _| {
13930                        (pane.preview_item_id(), pane.preview_item_idx())
13931                    });
13932
13933                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
13934
13935                if let Some(preview_item_id) = preview_item_id {
13936                    workspace.active_pane().update(cx, |pane, cx| {
13937                        pane.remove_item(preview_item_id, false, false, window, cx);
13938                    });
13939                }
13940            } else {
13941                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
13942            }
13943        }
13944        workspace.active_pane().update(cx, |pane, cx| {
13945            pane.set_preview_item_id(Some(item_id), cx);
13946        });
13947    }
13948
13949    pub fn rename(
13950        &mut self,
13951        _: &Rename,
13952        window: &mut Window,
13953        cx: &mut Context<Self>,
13954    ) -> Option<Task<Result<()>>> {
13955        use language::ToOffset as _;
13956
13957        let provider = self.semantics_provider.clone()?;
13958        let selection = self.selections.newest_anchor().clone();
13959        let (cursor_buffer, cursor_buffer_position) = self
13960            .buffer
13961            .read(cx)
13962            .text_anchor_for_position(selection.head(), cx)?;
13963        let (tail_buffer, cursor_buffer_position_end) = self
13964            .buffer
13965            .read(cx)
13966            .text_anchor_for_position(selection.tail(), cx)?;
13967        if tail_buffer != cursor_buffer {
13968            return None;
13969        }
13970
13971        let snapshot = cursor_buffer.read(cx).snapshot();
13972        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
13973        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
13974        let prepare_rename = provider
13975            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
13976            .unwrap_or_else(|| Task::ready(Ok(None)));
13977        drop(snapshot);
13978
13979        Some(cx.spawn_in(window, async move |this, cx| {
13980            let rename_range = if let Some(range) = prepare_rename.await? {
13981                Some(range)
13982            } else {
13983                this.update(cx, |this, cx| {
13984                    let buffer = this.buffer.read(cx).snapshot(cx);
13985                    let mut buffer_highlights = this
13986                        .document_highlights_for_position(selection.head(), &buffer)
13987                        .filter(|highlight| {
13988                            highlight.start.excerpt_id == selection.head().excerpt_id
13989                                && highlight.end.excerpt_id == selection.head().excerpt_id
13990                        });
13991                    buffer_highlights
13992                        .next()
13993                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
13994                })?
13995            };
13996            if let Some(rename_range) = rename_range {
13997                this.update_in(cx, |this, window, cx| {
13998                    let snapshot = cursor_buffer.read(cx).snapshot();
13999                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14000                    let cursor_offset_in_rename_range =
14001                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14002                    let cursor_offset_in_rename_range_end =
14003                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14004
14005                    this.take_rename(false, window, cx);
14006                    let buffer = this.buffer.read(cx).read(cx);
14007                    let cursor_offset = selection.head().to_offset(&buffer);
14008                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14009                    let rename_end = rename_start + rename_buffer_range.len();
14010                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14011                    let mut old_highlight_id = None;
14012                    let old_name: Arc<str> = buffer
14013                        .chunks(rename_start..rename_end, true)
14014                        .map(|chunk| {
14015                            if old_highlight_id.is_none() {
14016                                old_highlight_id = chunk.syntax_highlight_id;
14017                            }
14018                            chunk.text
14019                        })
14020                        .collect::<String>()
14021                        .into();
14022
14023                    drop(buffer);
14024
14025                    // Position the selection in the rename editor so that it matches the current selection.
14026                    this.show_local_selections = false;
14027                    let rename_editor = cx.new(|cx| {
14028                        let mut editor = Editor::single_line(window, cx);
14029                        editor.buffer.update(cx, |buffer, cx| {
14030                            buffer.edit([(0..0, old_name.clone())], None, cx)
14031                        });
14032                        let rename_selection_range = match cursor_offset_in_rename_range
14033                            .cmp(&cursor_offset_in_rename_range_end)
14034                        {
14035                            Ordering::Equal => {
14036                                editor.select_all(&SelectAll, window, cx);
14037                                return editor;
14038                            }
14039                            Ordering::Less => {
14040                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14041                            }
14042                            Ordering::Greater => {
14043                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14044                            }
14045                        };
14046                        if rename_selection_range.end > old_name.len() {
14047                            editor.select_all(&SelectAll, window, cx);
14048                        } else {
14049                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14050                                s.select_ranges([rename_selection_range]);
14051                            });
14052                        }
14053                        editor
14054                    });
14055                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14056                        if e == &EditorEvent::Focused {
14057                            cx.emit(EditorEvent::FocusedIn)
14058                        }
14059                    })
14060                    .detach();
14061
14062                    let write_highlights =
14063                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14064                    let read_highlights =
14065                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14066                    let ranges = write_highlights
14067                        .iter()
14068                        .flat_map(|(_, ranges)| ranges.iter())
14069                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14070                        .cloned()
14071                        .collect();
14072
14073                    this.highlight_text::<Rename>(
14074                        ranges,
14075                        HighlightStyle {
14076                            fade_out: Some(0.6),
14077                            ..Default::default()
14078                        },
14079                        cx,
14080                    );
14081                    let rename_focus_handle = rename_editor.focus_handle(cx);
14082                    window.focus(&rename_focus_handle);
14083                    let block_id = this.insert_blocks(
14084                        [BlockProperties {
14085                            style: BlockStyle::Flex,
14086                            placement: BlockPlacement::Below(range.start),
14087                            height: Some(1),
14088                            render: Arc::new({
14089                                let rename_editor = rename_editor.clone();
14090                                move |cx: &mut BlockContext| {
14091                                    let mut text_style = cx.editor_style.text.clone();
14092                                    if let Some(highlight_style) = old_highlight_id
14093                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14094                                    {
14095                                        text_style = text_style.highlight(highlight_style);
14096                                    }
14097                                    div()
14098                                        .block_mouse_down()
14099                                        .pl(cx.anchor_x)
14100                                        .child(EditorElement::new(
14101                                            &rename_editor,
14102                                            EditorStyle {
14103                                                background: cx.theme().system().transparent,
14104                                                local_player: cx.editor_style.local_player,
14105                                                text: text_style,
14106                                                scrollbar_width: cx.editor_style.scrollbar_width,
14107                                                syntax: cx.editor_style.syntax.clone(),
14108                                                status: cx.editor_style.status.clone(),
14109                                                inlay_hints_style: HighlightStyle {
14110                                                    font_weight: Some(FontWeight::BOLD),
14111                                                    ..make_inlay_hints_style(cx.app)
14112                                                },
14113                                                inline_completion_styles: make_suggestion_styles(
14114                                                    cx.app,
14115                                                ),
14116                                                ..EditorStyle::default()
14117                                            },
14118                                        ))
14119                                        .into_any_element()
14120                                }
14121                            }),
14122                            priority: 0,
14123                        }],
14124                        Some(Autoscroll::fit()),
14125                        cx,
14126                    )[0];
14127                    this.pending_rename = Some(RenameState {
14128                        range,
14129                        old_name,
14130                        editor: rename_editor,
14131                        block_id,
14132                    });
14133                })?;
14134            }
14135
14136            Ok(())
14137        }))
14138    }
14139
14140    pub fn confirm_rename(
14141        &mut self,
14142        _: &ConfirmRename,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) -> Option<Task<Result<()>>> {
14146        let rename = self.take_rename(false, window, cx)?;
14147        let workspace = self.workspace()?.downgrade();
14148        let (buffer, start) = self
14149            .buffer
14150            .read(cx)
14151            .text_anchor_for_position(rename.range.start, cx)?;
14152        let (end_buffer, _) = self
14153            .buffer
14154            .read(cx)
14155            .text_anchor_for_position(rename.range.end, cx)?;
14156        if buffer != end_buffer {
14157            return None;
14158        }
14159
14160        let old_name = rename.old_name;
14161        let new_name = rename.editor.read(cx).text(cx);
14162
14163        let rename = self.semantics_provider.as_ref()?.perform_rename(
14164            &buffer,
14165            start,
14166            new_name.clone(),
14167            cx,
14168        )?;
14169
14170        Some(cx.spawn_in(window, async move |editor, cx| {
14171            let project_transaction = rename.await?;
14172            Self::open_project_transaction(
14173                &editor,
14174                workspace,
14175                project_transaction,
14176                format!("Rename: {}{}", old_name, new_name),
14177                cx,
14178            )
14179            .await?;
14180
14181            editor.update(cx, |editor, cx| {
14182                editor.refresh_document_highlights(cx);
14183            })?;
14184            Ok(())
14185        }))
14186    }
14187
14188    fn take_rename(
14189        &mut self,
14190        moving_cursor: bool,
14191        window: &mut Window,
14192        cx: &mut Context<Self>,
14193    ) -> Option<RenameState> {
14194        let rename = self.pending_rename.take()?;
14195        if rename.editor.focus_handle(cx).is_focused(window) {
14196            window.focus(&self.focus_handle);
14197        }
14198
14199        self.remove_blocks(
14200            [rename.block_id].into_iter().collect(),
14201            Some(Autoscroll::fit()),
14202            cx,
14203        );
14204        self.clear_highlights::<Rename>(cx);
14205        self.show_local_selections = true;
14206
14207        if moving_cursor {
14208            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14209                editor.selections.newest::<usize>(cx).head()
14210            });
14211
14212            // Update the selection to match the position of the selection inside
14213            // the rename editor.
14214            let snapshot = self.buffer.read(cx).read(cx);
14215            let rename_range = rename.range.to_offset(&snapshot);
14216            let cursor_in_editor = snapshot
14217                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14218                .min(rename_range.end);
14219            drop(snapshot);
14220
14221            self.change_selections(None, window, cx, |s| {
14222                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14223            });
14224        } else {
14225            self.refresh_document_highlights(cx);
14226        }
14227
14228        Some(rename)
14229    }
14230
14231    pub fn pending_rename(&self) -> Option<&RenameState> {
14232        self.pending_rename.as_ref()
14233    }
14234
14235    fn format(
14236        &mut self,
14237        _: &Format,
14238        window: &mut Window,
14239        cx: &mut Context<Self>,
14240    ) -> Option<Task<Result<()>>> {
14241        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14242
14243        let project = match &self.project {
14244            Some(project) => project.clone(),
14245            None => return None,
14246        };
14247
14248        Some(self.perform_format(
14249            project,
14250            FormatTrigger::Manual,
14251            FormatTarget::Buffers,
14252            window,
14253            cx,
14254        ))
14255    }
14256
14257    fn format_selections(
14258        &mut self,
14259        _: &FormatSelections,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) -> Option<Task<Result<()>>> {
14263        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14264
14265        let project = match &self.project {
14266            Some(project) => project.clone(),
14267            None => return None,
14268        };
14269
14270        let ranges = self
14271            .selections
14272            .all_adjusted(cx)
14273            .into_iter()
14274            .map(|selection| selection.range())
14275            .collect_vec();
14276
14277        Some(self.perform_format(
14278            project,
14279            FormatTrigger::Manual,
14280            FormatTarget::Ranges(ranges),
14281            window,
14282            cx,
14283        ))
14284    }
14285
14286    fn perform_format(
14287        &mut self,
14288        project: Entity<Project>,
14289        trigger: FormatTrigger,
14290        target: FormatTarget,
14291        window: &mut Window,
14292        cx: &mut Context<Self>,
14293    ) -> Task<Result<()>> {
14294        let buffer = self.buffer.clone();
14295        let (buffers, target) = match target {
14296            FormatTarget::Buffers => {
14297                let mut buffers = buffer.read(cx).all_buffers();
14298                if trigger == FormatTrigger::Save {
14299                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
14300                }
14301                (buffers, LspFormatTarget::Buffers)
14302            }
14303            FormatTarget::Ranges(selection_ranges) => {
14304                let multi_buffer = buffer.read(cx);
14305                let snapshot = multi_buffer.read(cx);
14306                let mut buffers = HashSet::default();
14307                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
14308                    BTreeMap::new();
14309                for selection_range in selection_ranges {
14310                    for (buffer, buffer_range, _) in
14311                        snapshot.range_to_buffer_ranges(selection_range)
14312                    {
14313                        let buffer_id = buffer.remote_id();
14314                        let start = buffer.anchor_before(buffer_range.start);
14315                        let end = buffer.anchor_after(buffer_range.end);
14316                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
14317                        buffer_id_to_ranges
14318                            .entry(buffer_id)
14319                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
14320                            .or_insert_with(|| vec![start..end]);
14321                    }
14322                }
14323                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
14324            }
14325        };
14326
14327        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
14328        let selections_prev = transaction_id_prev
14329            .and_then(|transaction_id_prev| {
14330                // default to selections as they were after the last edit, if we have them,
14331                // instead of how they are now.
14332                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
14333                // will take you back to where you made the last edit, instead of staying where you scrolled
14334                self.selection_history
14335                    .transaction(transaction_id_prev)
14336                    .map(|t| t.0.clone())
14337            })
14338            .unwrap_or_else(|| {
14339                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
14340                self.selections.disjoint_anchors()
14341            });
14342
14343        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
14344        let format = project.update(cx, |project, cx| {
14345            project.format(buffers, target, true, trigger, cx)
14346        });
14347
14348        cx.spawn_in(window, async move |editor, cx| {
14349            let transaction = futures::select_biased! {
14350                transaction = format.log_err().fuse() => transaction,
14351                () = timeout => {
14352                    log::warn!("timed out waiting for formatting");
14353                    None
14354                }
14355            };
14356
14357            buffer
14358                .update(cx, |buffer, cx| {
14359                    if let Some(transaction) = transaction {
14360                        if !buffer.is_singleton() {
14361                            buffer.push_transaction(&transaction.0, cx);
14362                        }
14363                    }
14364                    cx.notify();
14365                })
14366                .ok();
14367
14368            if let Some(transaction_id_now) =
14369                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
14370            {
14371                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
14372                if has_new_transaction {
14373                    _ = editor.update(cx, |editor, _| {
14374                        editor
14375                            .selection_history
14376                            .insert_transaction(transaction_id_now, selections_prev);
14377                    });
14378                }
14379            }
14380
14381            Ok(())
14382        })
14383    }
14384
14385    fn organize_imports(
14386        &mut self,
14387        _: &OrganizeImports,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) -> Option<Task<Result<()>>> {
14391        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14392        let project = match &self.project {
14393            Some(project) => project.clone(),
14394            None => return None,
14395        };
14396        Some(self.perform_code_action_kind(
14397            project,
14398            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
14399            window,
14400            cx,
14401        ))
14402    }
14403
14404    fn perform_code_action_kind(
14405        &mut self,
14406        project: Entity<Project>,
14407        kind: CodeActionKind,
14408        window: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) -> Task<Result<()>> {
14411        let buffer = self.buffer.clone();
14412        let buffers = buffer.read(cx).all_buffers();
14413        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
14414        let apply_action = project.update(cx, |project, cx| {
14415            project.apply_code_action_kind(buffers, kind, true, cx)
14416        });
14417        cx.spawn_in(window, async move |_, cx| {
14418            let transaction = futures::select_biased! {
14419                () = timeout => {
14420                    log::warn!("timed out waiting for executing code action");
14421                    None
14422                }
14423                transaction = apply_action.log_err().fuse() => transaction,
14424            };
14425            buffer
14426                .update(cx, |buffer, cx| {
14427                    // check if we need this
14428                    if let Some(transaction) = transaction {
14429                        if !buffer.is_singleton() {
14430                            buffer.push_transaction(&transaction.0, cx);
14431                        }
14432                    }
14433                    cx.notify();
14434                })
14435                .ok();
14436            Ok(())
14437        })
14438    }
14439
14440    fn restart_language_server(
14441        &mut self,
14442        _: &RestartLanguageServer,
14443        _: &mut Window,
14444        cx: &mut Context<Self>,
14445    ) {
14446        if let Some(project) = self.project.clone() {
14447            self.buffer.update(cx, |multi_buffer, cx| {
14448                project.update(cx, |project, cx| {
14449                    project.restart_language_servers_for_buffers(
14450                        multi_buffer.all_buffers().into_iter().collect(),
14451                        cx,
14452                    );
14453                });
14454            })
14455        }
14456    }
14457
14458    fn stop_language_server(
14459        &mut self,
14460        _: &StopLanguageServer,
14461        _: &mut Window,
14462        cx: &mut Context<Self>,
14463    ) {
14464        if let Some(project) = self.project.clone() {
14465            self.buffer.update(cx, |multi_buffer, cx| {
14466                project.update(cx, |project, cx| {
14467                    project.stop_language_servers_for_buffers(
14468                        multi_buffer.all_buffers().into_iter().collect(),
14469                        cx,
14470                    );
14471                    cx.emit(project::Event::RefreshInlayHints);
14472                });
14473            });
14474        }
14475    }
14476
14477    fn cancel_language_server_work(
14478        workspace: &mut Workspace,
14479        _: &actions::CancelLanguageServerWork,
14480        _: &mut Window,
14481        cx: &mut Context<Workspace>,
14482    ) {
14483        let project = workspace.project();
14484        let buffers = workspace
14485            .active_item(cx)
14486            .and_then(|item| item.act_as::<Editor>(cx))
14487            .map_or(HashSet::default(), |editor| {
14488                editor.read(cx).buffer.read(cx).all_buffers()
14489            });
14490        project.update(cx, |project, cx| {
14491            project.cancel_language_server_work_for_buffers(buffers, cx);
14492        });
14493    }
14494
14495    fn show_character_palette(
14496        &mut self,
14497        _: &ShowCharacterPalette,
14498        window: &mut Window,
14499        _: &mut Context<Self>,
14500    ) {
14501        window.show_character_palette();
14502    }
14503
14504    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
14505        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
14506            let buffer = self.buffer.read(cx).snapshot(cx);
14507            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
14508            let primary_range_end = active_diagnostics.primary_range.end.to_offset(&buffer);
14509            let is_valid = buffer
14510                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
14511                .any(|entry| {
14512                    entry.diagnostic.is_primary
14513                        && !entry.range.is_empty()
14514                        && entry.range.start == primary_range_start
14515                        && entry.diagnostic.message == active_diagnostics.primary_message
14516                });
14517
14518            if is_valid != active_diagnostics.is_valid {
14519                active_diagnostics.is_valid = is_valid;
14520                if is_valid {
14521                    let mut new_styles = HashMap::default();
14522                    for (block_id, diagnostic) in &active_diagnostics.blocks {
14523                        new_styles.insert(
14524                            *block_id,
14525                            diagnostic_block_renderer(diagnostic.clone(), None, true),
14526                        );
14527                    }
14528                    self.display_map.update(cx, |display_map, _cx| {
14529                        display_map.replace_blocks(new_styles);
14530                    });
14531                } else {
14532                    self.dismiss_diagnostics(cx);
14533                }
14534            }
14535        }
14536    }
14537
14538    fn activate_diagnostics(
14539        &mut self,
14540        buffer_id: BufferId,
14541        group_id: usize,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) {
14545        self.dismiss_diagnostics(cx);
14546        let snapshot = self.snapshot(window, cx);
14547        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
14548            let buffer = self.buffer.read(cx).snapshot(cx);
14549
14550            let mut primary_range = None;
14551            let mut primary_message = None;
14552            let diagnostic_group = buffer
14553                .diagnostic_group(buffer_id, group_id)
14554                .filter_map(|entry| {
14555                    let start = entry.range.start;
14556                    let end = entry.range.end;
14557                    if snapshot.is_line_folded(MultiBufferRow(start.row))
14558                        && (start.row == end.row
14559                            || snapshot.is_line_folded(MultiBufferRow(end.row)))
14560                    {
14561                        return None;
14562                    }
14563                    if entry.diagnostic.is_primary {
14564                        primary_range = Some(entry.range.clone());
14565                        primary_message = Some(entry.diagnostic.message.clone());
14566                    }
14567                    Some(entry)
14568                })
14569                .collect::<Vec<_>>();
14570            let primary_range = primary_range?;
14571            let primary_message = primary_message?;
14572
14573            let blocks = display_map
14574                .insert_blocks(
14575                    diagnostic_group.iter().map(|entry| {
14576                        let diagnostic = entry.diagnostic.clone();
14577                        let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
14578                        BlockProperties {
14579                            style: BlockStyle::Fixed,
14580                            placement: BlockPlacement::Below(
14581                                buffer.anchor_after(entry.range.start),
14582                            ),
14583                            height: Some(message_height),
14584                            render: diagnostic_block_renderer(diagnostic, None, true),
14585                            priority: 0,
14586                        }
14587                    }),
14588                    cx,
14589                )
14590                .into_iter()
14591                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
14592                .collect();
14593
14594            Some(ActiveDiagnosticGroup {
14595                primary_range: buffer.anchor_before(primary_range.start)
14596                    ..buffer.anchor_after(primary_range.end),
14597                primary_message,
14598                group_id,
14599                blocks,
14600                is_valid: true,
14601            })
14602        });
14603    }
14604
14605    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
14606        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
14607            self.display_map.update(cx, |display_map, cx| {
14608                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
14609            });
14610            cx.notify();
14611        }
14612    }
14613
14614    /// Disable inline diagnostics rendering for this editor.
14615    pub fn disable_inline_diagnostics(&mut self) {
14616        self.inline_diagnostics_enabled = false;
14617        self.inline_diagnostics_update = Task::ready(());
14618        self.inline_diagnostics.clear();
14619    }
14620
14621    pub fn inline_diagnostics_enabled(&self) -> bool {
14622        self.inline_diagnostics_enabled
14623    }
14624
14625    pub fn show_inline_diagnostics(&self) -> bool {
14626        self.show_inline_diagnostics
14627    }
14628
14629    pub fn toggle_inline_diagnostics(
14630        &mut self,
14631        _: &ToggleInlineDiagnostics,
14632        window: &mut Window,
14633        cx: &mut Context<Editor>,
14634    ) {
14635        self.show_inline_diagnostics = !self.show_inline_diagnostics;
14636        self.refresh_inline_diagnostics(false, window, cx);
14637    }
14638
14639    fn refresh_inline_diagnostics(
14640        &mut self,
14641        debounce: bool,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) {
14645        if !self.inline_diagnostics_enabled || !self.show_inline_diagnostics {
14646            self.inline_diagnostics_update = Task::ready(());
14647            self.inline_diagnostics.clear();
14648            return;
14649        }
14650
14651        let debounce_ms = ProjectSettings::get_global(cx)
14652            .diagnostics
14653            .inline
14654            .update_debounce_ms;
14655        let debounce = if debounce && debounce_ms > 0 {
14656            Some(Duration::from_millis(debounce_ms))
14657        } else {
14658            None
14659        };
14660        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
14661            if let Some(debounce) = debounce {
14662                cx.background_executor().timer(debounce).await;
14663            }
14664            let Some(snapshot) = editor
14665                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
14666                .ok()
14667            else {
14668                return;
14669            };
14670
14671            let new_inline_diagnostics = cx
14672                .background_spawn(async move {
14673                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
14674                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
14675                        let message = diagnostic_entry
14676                            .diagnostic
14677                            .message
14678                            .split_once('\n')
14679                            .map(|(line, _)| line)
14680                            .map(SharedString::new)
14681                            .unwrap_or_else(|| {
14682                                SharedString::from(diagnostic_entry.diagnostic.message)
14683                            });
14684                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
14685                        let (Ok(i) | Err(i)) = inline_diagnostics
14686                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
14687                        inline_diagnostics.insert(
14688                            i,
14689                            (
14690                                start_anchor,
14691                                InlineDiagnostic {
14692                                    message,
14693                                    group_id: diagnostic_entry.diagnostic.group_id,
14694                                    start: diagnostic_entry.range.start.to_point(&snapshot),
14695                                    is_primary: diagnostic_entry.diagnostic.is_primary,
14696                                    severity: diagnostic_entry.diagnostic.severity,
14697                                },
14698                            ),
14699                        );
14700                    }
14701                    inline_diagnostics
14702                })
14703                .await;
14704
14705            editor
14706                .update(cx, |editor, cx| {
14707                    editor.inline_diagnostics = new_inline_diagnostics;
14708                    cx.notify();
14709                })
14710                .ok();
14711        });
14712    }
14713
14714    pub fn set_selections_from_remote(
14715        &mut self,
14716        selections: Vec<Selection<Anchor>>,
14717        pending_selection: Option<Selection<Anchor>>,
14718        window: &mut Window,
14719        cx: &mut Context<Self>,
14720    ) {
14721        let old_cursor_position = self.selections.newest_anchor().head();
14722        self.selections.change_with(cx, |s| {
14723            s.select_anchors(selections);
14724            if let Some(pending_selection) = pending_selection {
14725                s.set_pending(pending_selection, SelectMode::Character);
14726            } else {
14727                s.clear_pending();
14728            }
14729        });
14730        self.selections_did_change(false, &old_cursor_position, true, window, cx);
14731    }
14732
14733    fn push_to_selection_history(&mut self) {
14734        self.selection_history.push(SelectionHistoryEntry {
14735            selections: self.selections.disjoint_anchors(),
14736            select_next_state: self.select_next_state.clone(),
14737            select_prev_state: self.select_prev_state.clone(),
14738            add_selections_state: self.add_selections_state.clone(),
14739        });
14740    }
14741
14742    pub fn transact(
14743        &mut self,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
14747    ) -> Option<TransactionId> {
14748        self.start_transaction_at(Instant::now(), window, cx);
14749        update(self, window, cx);
14750        self.end_transaction_at(Instant::now(), cx)
14751    }
14752
14753    pub fn start_transaction_at(
14754        &mut self,
14755        now: Instant,
14756        window: &mut Window,
14757        cx: &mut Context<Self>,
14758    ) {
14759        self.end_selection(window, cx);
14760        if let Some(tx_id) = self
14761            .buffer
14762            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
14763        {
14764            self.selection_history
14765                .insert_transaction(tx_id, self.selections.disjoint_anchors());
14766            cx.emit(EditorEvent::TransactionBegun {
14767                transaction_id: tx_id,
14768            })
14769        }
14770    }
14771
14772    pub fn end_transaction_at(
14773        &mut self,
14774        now: Instant,
14775        cx: &mut Context<Self>,
14776    ) -> Option<TransactionId> {
14777        if let Some(transaction_id) = self
14778            .buffer
14779            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
14780        {
14781            if let Some((_, end_selections)) =
14782                self.selection_history.transaction_mut(transaction_id)
14783            {
14784                *end_selections = Some(self.selections.disjoint_anchors());
14785            } else {
14786                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
14787            }
14788
14789            cx.emit(EditorEvent::Edited { transaction_id });
14790            Some(transaction_id)
14791        } else {
14792            None
14793        }
14794    }
14795
14796    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
14797        if self.selection_mark_mode {
14798            self.change_selections(None, window, cx, |s| {
14799                s.move_with(|_, sel| {
14800                    sel.collapse_to(sel.head(), SelectionGoal::None);
14801                });
14802            })
14803        }
14804        self.selection_mark_mode = true;
14805        cx.notify();
14806    }
14807
14808    pub fn swap_selection_ends(
14809        &mut self,
14810        _: &actions::SwapSelectionEnds,
14811        window: &mut Window,
14812        cx: &mut Context<Self>,
14813    ) {
14814        self.change_selections(None, window, cx, |s| {
14815            s.move_with(|_, sel| {
14816                if sel.start != sel.end {
14817                    sel.reversed = !sel.reversed
14818                }
14819            });
14820        });
14821        self.request_autoscroll(Autoscroll::newest(), cx);
14822        cx.notify();
14823    }
14824
14825    pub fn toggle_fold(
14826        &mut self,
14827        _: &actions::ToggleFold,
14828        window: &mut Window,
14829        cx: &mut Context<Self>,
14830    ) {
14831        if self.is_singleton(cx) {
14832            let selection = self.selections.newest::<Point>(cx);
14833
14834            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14835            let range = if selection.is_empty() {
14836                let point = selection.head().to_display_point(&display_map);
14837                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
14838                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
14839                    .to_point(&display_map);
14840                start..end
14841            } else {
14842                selection.range()
14843            };
14844            if display_map.folds_in_range(range).next().is_some() {
14845                self.unfold_lines(&Default::default(), window, cx)
14846            } else {
14847                self.fold(&Default::default(), window, cx)
14848            }
14849        } else {
14850            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
14851            let buffer_ids: HashSet<_> = self
14852                .selections
14853                .disjoint_anchor_ranges()
14854                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
14855                .collect();
14856
14857            let should_unfold = buffer_ids
14858                .iter()
14859                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
14860
14861            for buffer_id in buffer_ids {
14862                if should_unfold {
14863                    self.unfold_buffer(buffer_id, cx);
14864                } else {
14865                    self.fold_buffer(buffer_id, cx);
14866                }
14867            }
14868        }
14869    }
14870
14871    pub fn toggle_fold_recursive(
14872        &mut self,
14873        _: &actions::ToggleFoldRecursive,
14874        window: &mut Window,
14875        cx: &mut Context<Self>,
14876    ) {
14877        let selection = self.selections.newest::<Point>(cx);
14878
14879        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14880        let range = if selection.is_empty() {
14881            let point = selection.head().to_display_point(&display_map);
14882            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
14883            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
14884                .to_point(&display_map);
14885            start..end
14886        } else {
14887            selection.range()
14888        };
14889        if display_map.folds_in_range(range).next().is_some() {
14890            self.unfold_recursive(&Default::default(), window, cx)
14891        } else {
14892            self.fold_recursive(&Default::default(), window, cx)
14893        }
14894    }
14895
14896    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
14897        if self.is_singleton(cx) {
14898            let mut to_fold = Vec::new();
14899            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14900            let selections = self.selections.all_adjusted(cx);
14901
14902            for selection in selections {
14903                let range = selection.range().sorted();
14904                let buffer_start_row = range.start.row;
14905
14906                if range.start.row != range.end.row {
14907                    let mut found = false;
14908                    let mut row = range.start.row;
14909                    while row <= range.end.row {
14910                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
14911                        {
14912                            found = true;
14913                            row = crease.range().end.row + 1;
14914                            to_fold.push(crease);
14915                        } else {
14916                            row += 1
14917                        }
14918                    }
14919                    if found {
14920                        continue;
14921                    }
14922                }
14923
14924                for row in (0..=range.start.row).rev() {
14925                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
14926                        if crease.range().end.row >= buffer_start_row {
14927                            to_fold.push(crease);
14928                            if row <= range.start.row {
14929                                break;
14930                            }
14931                        }
14932                    }
14933                }
14934            }
14935
14936            self.fold_creases(to_fold, true, window, cx);
14937        } else {
14938            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
14939            let buffer_ids = self
14940                .selections
14941                .disjoint_anchor_ranges()
14942                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
14943                .collect::<HashSet<_>>();
14944            for buffer_id in buffer_ids {
14945                self.fold_buffer(buffer_id, cx);
14946            }
14947        }
14948    }
14949
14950    fn fold_at_level(
14951        &mut self,
14952        fold_at: &FoldAtLevel,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        if !self.buffer.read(cx).is_singleton() {
14957            return;
14958        }
14959
14960        let fold_at_level = fold_at.0;
14961        let snapshot = self.buffer.read(cx).snapshot(cx);
14962        let mut to_fold = Vec::new();
14963        let mut stack = vec![(0, snapshot.max_row().0, 1)];
14964
14965        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
14966            while start_row < end_row {
14967                match self
14968                    .snapshot(window, cx)
14969                    .crease_for_buffer_row(MultiBufferRow(start_row))
14970                {
14971                    Some(crease) => {
14972                        let nested_start_row = crease.range().start.row + 1;
14973                        let nested_end_row = crease.range().end.row;
14974
14975                        if current_level < fold_at_level {
14976                            stack.push((nested_start_row, nested_end_row, current_level + 1));
14977                        } else if current_level == fold_at_level {
14978                            to_fold.push(crease);
14979                        }
14980
14981                        start_row = nested_end_row + 1;
14982                    }
14983                    None => start_row += 1,
14984                }
14985            }
14986        }
14987
14988        self.fold_creases(to_fold, true, window, cx);
14989    }
14990
14991    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
14992        if self.buffer.read(cx).is_singleton() {
14993            let mut fold_ranges = Vec::new();
14994            let snapshot = self.buffer.read(cx).snapshot(cx);
14995
14996            for row in 0..snapshot.max_row().0 {
14997                if let Some(foldable_range) = self
14998                    .snapshot(window, cx)
14999                    .crease_for_buffer_row(MultiBufferRow(row))
15000                {
15001                    fold_ranges.push(foldable_range);
15002                }
15003            }
15004
15005            self.fold_creases(fold_ranges, true, window, cx);
15006        } else {
15007            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15008                editor
15009                    .update_in(cx, |editor, _, cx| {
15010                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15011                            editor.fold_buffer(buffer_id, cx);
15012                        }
15013                    })
15014                    .ok();
15015            });
15016        }
15017    }
15018
15019    pub fn fold_function_bodies(
15020        &mut self,
15021        _: &actions::FoldFunctionBodies,
15022        window: &mut Window,
15023        cx: &mut Context<Self>,
15024    ) {
15025        let snapshot = self.buffer.read(cx).snapshot(cx);
15026
15027        let ranges = snapshot
15028            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15029            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15030            .collect::<Vec<_>>();
15031
15032        let creases = ranges
15033            .into_iter()
15034            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15035            .collect();
15036
15037        self.fold_creases(creases, true, window, cx);
15038    }
15039
15040    pub fn fold_recursive(
15041        &mut self,
15042        _: &actions::FoldRecursive,
15043        window: &mut Window,
15044        cx: &mut Context<Self>,
15045    ) {
15046        let mut to_fold = Vec::new();
15047        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15048        let selections = self.selections.all_adjusted(cx);
15049
15050        for selection in selections {
15051            let range = selection.range().sorted();
15052            let buffer_start_row = range.start.row;
15053
15054            if range.start.row != range.end.row {
15055                let mut found = false;
15056                for row in range.start.row..=range.end.row {
15057                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15058                        found = true;
15059                        to_fold.push(crease);
15060                    }
15061                }
15062                if found {
15063                    continue;
15064                }
15065            }
15066
15067            for row in (0..=range.start.row).rev() {
15068                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15069                    if crease.range().end.row >= buffer_start_row {
15070                        to_fold.push(crease);
15071                    } else {
15072                        break;
15073                    }
15074                }
15075            }
15076        }
15077
15078        self.fold_creases(to_fold, true, window, cx);
15079    }
15080
15081    pub fn fold_at(
15082        &mut self,
15083        buffer_row: MultiBufferRow,
15084        window: &mut Window,
15085        cx: &mut Context<Self>,
15086    ) {
15087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15088
15089        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15090            let autoscroll = self
15091                .selections
15092                .all::<Point>(cx)
15093                .iter()
15094                .any(|selection| crease.range().overlaps(&selection.range()));
15095
15096            self.fold_creases(vec![crease], autoscroll, window, cx);
15097        }
15098    }
15099
15100    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15101        if self.is_singleton(cx) {
15102            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15103            let buffer = &display_map.buffer_snapshot;
15104            let selections = self.selections.all::<Point>(cx);
15105            let ranges = selections
15106                .iter()
15107                .map(|s| {
15108                    let range = s.display_range(&display_map).sorted();
15109                    let mut start = range.start.to_point(&display_map);
15110                    let mut end = range.end.to_point(&display_map);
15111                    start.column = 0;
15112                    end.column = buffer.line_len(MultiBufferRow(end.row));
15113                    start..end
15114                })
15115                .collect::<Vec<_>>();
15116
15117            self.unfold_ranges(&ranges, true, true, cx);
15118        } else {
15119            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15120            let buffer_ids = self
15121                .selections
15122                .disjoint_anchor_ranges()
15123                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15124                .collect::<HashSet<_>>();
15125            for buffer_id in buffer_ids {
15126                self.unfold_buffer(buffer_id, cx);
15127            }
15128        }
15129    }
15130
15131    pub fn unfold_recursive(
15132        &mut self,
15133        _: &UnfoldRecursive,
15134        _window: &mut Window,
15135        cx: &mut Context<Self>,
15136    ) {
15137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15138        let selections = self.selections.all::<Point>(cx);
15139        let ranges = selections
15140            .iter()
15141            .map(|s| {
15142                let mut range = s.display_range(&display_map).sorted();
15143                *range.start.column_mut() = 0;
15144                *range.end.column_mut() = display_map.line_len(range.end.row());
15145                let start = range.start.to_point(&display_map);
15146                let end = range.end.to_point(&display_map);
15147                start..end
15148            })
15149            .collect::<Vec<_>>();
15150
15151        self.unfold_ranges(&ranges, true, true, cx);
15152    }
15153
15154    pub fn unfold_at(
15155        &mut self,
15156        buffer_row: MultiBufferRow,
15157        _window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) {
15160        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15161
15162        let intersection_range = Point::new(buffer_row.0, 0)
15163            ..Point::new(
15164                buffer_row.0,
15165                display_map.buffer_snapshot.line_len(buffer_row),
15166            );
15167
15168        let autoscroll = self
15169            .selections
15170            .all::<Point>(cx)
15171            .iter()
15172            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15173
15174        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15175    }
15176
15177    pub fn unfold_all(
15178        &mut self,
15179        _: &actions::UnfoldAll,
15180        _window: &mut Window,
15181        cx: &mut Context<Self>,
15182    ) {
15183        if self.buffer.read(cx).is_singleton() {
15184            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15185            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15186        } else {
15187            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15188                editor
15189                    .update(cx, |editor, cx| {
15190                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15191                            editor.unfold_buffer(buffer_id, cx);
15192                        }
15193                    })
15194                    .ok();
15195            });
15196        }
15197    }
15198
15199    pub fn fold_selected_ranges(
15200        &mut self,
15201        _: &FoldSelectedRanges,
15202        window: &mut Window,
15203        cx: &mut Context<Self>,
15204    ) {
15205        let selections = self.selections.all_adjusted(cx);
15206        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15207        let ranges = selections
15208            .into_iter()
15209            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15210            .collect::<Vec<_>>();
15211        self.fold_creases(ranges, true, window, cx);
15212    }
15213
15214    pub fn fold_ranges<T: ToOffset + Clone>(
15215        &mut self,
15216        ranges: Vec<Range<T>>,
15217        auto_scroll: bool,
15218        window: &mut Window,
15219        cx: &mut Context<Self>,
15220    ) {
15221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15222        let ranges = ranges
15223            .into_iter()
15224            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15225            .collect::<Vec<_>>();
15226        self.fold_creases(ranges, auto_scroll, window, cx);
15227    }
15228
15229    pub fn fold_creases<T: ToOffset + Clone>(
15230        &mut self,
15231        creases: Vec<Crease<T>>,
15232        auto_scroll: bool,
15233        window: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) {
15236        if creases.is_empty() {
15237            return;
15238        }
15239
15240        let mut buffers_affected = HashSet::default();
15241        let multi_buffer = self.buffer().read(cx);
15242        for crease in &creases {
15243            if let Some((_, buffer, _)) =
15244                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15245            {
15246                buffers_affected.insert(buffer.read(cx).remote_id());
15247            };
15248        }
15249
15250        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
15251
15252        if auto_scroll {
15253            self.request_autoscroll(Autoscroll::fit(), cx);
15254        }
15255
15256        cx.notify();
15257
15258        if let Some(active_diagnostics) = self.active_diagnostics.take() {
15259            // Clear diagnostics block when folding a range that contains it.
15260            let snapshot = self.snapshot(window, cx);
15261            if snapshot.intersects_fold(active_diagnostics.primary_range.start) {
15262                drop(snapshot);
15263                self.active_diagnostics = Some(active_diagnostics);
15264                self.dismiss_diagnostics(cx);
15265            } else {
15266                self.active_diagnostics = Some(active_diagnostics);
15267            }
15268        }
15269
15270        self.scrollbar_marker_state.dirty = true;
15271        self.folds_did_change(cx);
15272    }
15273
15274    /// Removes any folds whose ranges intersect any of the given ranges.
15275    pub fn unfold_ranges<T: ToOffset + Clone>(
15276        &mut self,
15277        ranges: &[Range<T>],
15278        inclusive: bool,
15279        auto_scroll: bool,
15280        cx: &mut Context<Self>,
15281    ) {
15282        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15283            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
15284        });
15285        self.folds_did_change(cx);
15286    }
15287
15288    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15289        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
15290            return;
15291        }
15292        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15293        self.display_map.update(cx, |display_map, cx| {
15294            display_map.fold_buffers([buffer_id], cx)
15295        });
15296        cx.emit(EditorEvent::BufferFoldToggled {
15297            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
15298            folded: true,
15299        });
15300        cx.notify();
15301    }
15302
15303    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15304        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
15305            return;
15306        }
15307        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15308        self.display_map.update(cx, |display_map, cx| {
15309            display_map.unfold_buffers([buffer_id], cx);
15310        });
15311        cx.emit(EditorEvent::BufferFoldToggled {
15312            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
15313            folded: false,
15314        });
15315        cx.notify();
15316    }
15317
15318    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
15319        self.display_map.read(cx).is_buffer_folded(buffer)
15320    }
15321
15322    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
15323        self.display_map.read(cx).folded_buffers()
15324    }
15325
15326    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15327        self.display_map.update(cx, |display_map, cx| {
15328            display_map.disable_header_for_buffer(buffer_id, cx);
15329        });
15330        cx.notify();
15331    }
15332
15333    /// Removes any folds with the given ranges.
15334    pub fn remove_folds_with_type<T: ToOffset + Clone>(
15335        &mut self,
15336        ranges: &[Range<T>],
15337        type_id: TypeId,
15338        auto_scroll: bool,
15339        cx: &mut Context<Self>,
15340    ) {
15341        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15342            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
15343        });
15344        self.folds_did_change(cx);
15345    }
15346
15347    fn remove_folds_with<T: ToOffset + Clone>(
15348        &mut self,
15349        ranges: &[Range<T>],
15350        auto_scroll: bool,
15351        cx: &mut Context<Self>,
15352        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
15353    ) {
15354        if ranges.is_empty() {
15355            return;
15356        }
15357
15358        let mut buffers_affected = HashSet::default();
15359        let multi_buffer = self.buffer().read(cx);
15360        for range in ranges {
15361            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
15362                buffers_affected.insert(buffer.read(cx).remote_id());
15363            };
15364        }
15365
15366        self.display_map.update(cx, update);
15367
15368        if auto_scroll {
15369            self.request_autoscroll(Autoscroll::fit(), cx);
15370        }
15371
15372        cx.notify();
15373        self.scrollbar_marker_state.dirty = true;
15374        self.active_indent_guides_state.dirty = true;
15375    }
15376
15377    pub fn update_fold_widths(
15378        &mut self,
15379        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
15380        cx: &mut Context<Self>,
15381    ) -> bool {
15382        self.display_map
15383            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
15384    }
15385
15386    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
15387        self.display_map.read(cx).fold_placeholder.clone()
15388    }
15389
15390    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
15391        self.buffer.update(cx, |buffer, cx| {
15392            buffer.set_all_diff_hunks_expanded(cx);
15393        });
15394    }
15395
15396    pub fn expand_all_diff_hunks(
15397        &mut self,
15398        _: &ExpandAllDiffHunks,
15399        _window: &mut Window,
15400        cx: &mut Context<Self>,
15401    ) {
15402        self.buffer.update(cx, |buffer, cx| {
15403            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
15404        });
15405    }
15406
15407    pub fn toggle_selected_diff_hunks(
15408        &mut self,
15409        _: &ToggleSelectedDiffHunks,
15410        _window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) {
15413        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15414        self.toggle_diff_hunks_in_ranges(ranges, cx);
15415    }
15416
15417    pub fn diff_hunks_in_ranges<'a>(
15418        &'a self,
15419        ranges: &'a [Range<Anchor>],
15420        buffer: &'a MultiBufferSnapshot,
15421    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
15422        ranges.iter().flat_map(move |range| {
15423            let end_excerpt_id = range.end.excerpt_id;
15424            let range = range.to_point(buffer);
15425            let mut peek_end = range.end;
15426            if range.end.row < buffer.max_row().0 {
15427                peek_end = Point::new(range.end.row + 1, 0);
15428            }
15429            buffer
15430                .diff_hunks_in_range(range.start..peek_end)
15431                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
15432        })
15433    }
15434
15435    pub fn has_stageable_diff_hunks_in_ranges(
15436        &self,
15437        ranges: &[Range<Anchor>],
15438        snapshot: &MultiBufferSnapshot,
15439    ) -> bool {
15440        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
15441        hunks.any(|hunk| hunk.status().has_secondary_hunk())
15442    }
15443
15444    pub fn toggle_staged_selected_diff_hunks(
15445        &mut self,
15446        _: &::git::ToggleStaged,
15447        _: &mut Window,
15448        cx: &mut Context<Self>,
15449    ) {
15450        let snapshot = self.buffer.read(cx).snapshot(cx);
15451        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15452        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
15453        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15454    }
15455
15456    pub fn set_render_diff_hunk_controls(
15457        &mut self,
15458        render_diff_hunk_controls: RenderDiffHunkControlsFn,
15459        cx: &mut Context<Self>,
15460    ) {
15461        self.render_diff_hunk_controls = render_diff_hunk_controls;
15462        cx.notify();
15463    }
15464
15465    pub fn stage_and_next(
15466        &mut self,
15467        _: &::git::StageAndNext,
15468        window: &mut Window,
15469        cx: &mut Context<Self>,
15470    ) {
15471        self.do_stage_or_unstage_and_next(true, window, cx);
15472    }
15473
15474    pub fn unstage_and_next(
15475        &mut self,
15476        _: &::git::UnstageAndNext,
15477        window: &mut Window,
15478        cx: &mut Context<Self>,
15479    ) {
15480        self.do_stage_or_unstage_and_next(false, window, cx);
15481    }
15482
15483    pub fn stage_or_unstage_diff_hunks(
15484        &mut self,
15485        stage: bool,
15486        ranges: Vec<Range<Anchor>>,
15487        cx: &mut Context<Self>,
15488    ) {
15489        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
15490        cx.spawn(async move |this, cx| {
15491            task.await?;
15492            this.update(cx, |this, cx| {
15493                let snapshot = this.buffer.read(cx).snapshot(cx);
15494                let chunk_by = this
15495                    .diff_hunks_in_ranges(&ranges, &snapshot)
15496                    .chunk_by(|hunk| hunk.buffer_id);
15497                for (buffer_id, hunks) in &chunk_by {
15498                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
15499                }
15500            })
15501        })
15502        .detach_and_log_err(cx);
15503    }
15504
15505    fn save_buffers_for_ranges_if_needed(
15506        &mut self,
15507        ranges: &[Range<Anchor>],
15508        cx: &mut Context<Editor>,
15509    ) -> Task<Result<()>> {
15510        let multibuffer = self.buffer.read(cx);
15511        let snapshot = multibuffer.read(cx);
15512        let buffer_ids: HashSet<_> = ranges
15513            .iter()
15514            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
15515            .collect();
15516        drop(snapshot);
15517
15518        let mut buffers = HashSet::default();
15519        for buffer_id in buffer_ids {
15520            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
15521                let buffer = buffer_entity.read(cx);
15522                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
15523                {
15524                    buffers.insert(buffer_entity);
15525                }
15526            }
15527        }
15528
15529        if let Some(project) = &self.project {
15530            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
15531        } else {
15532            Task::ready(Ok(()))
15533        }
15534    }
15535
15536    fn do_stage_or_unstage_and_next(
15537        &mut self,
15538        stage: bool,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) {
15542        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
15543
15544        if ranges.iter().any(|range| range.start != range.end) {
15545            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15546            return;
15547        }
15548
15549        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15550        let snapshot = self.snapshot(window, cx);
15551        let position = self.selections.newest::<Point>(cx).head();
15552        let mut row = snapshot
15553            .buffer_snapshot
15554            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15555            .find(|hunk| hunk.row_range.start.0 > position.row)
15556            .map(|hunk| hunk.row_range.start);
15557
15558        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
15559        // Outside of the project diff editor, wrap around to the beginning.
15560        if !all_diff_hunks_expanded {
15561            row = row.or_else(|| {
15562                snapshot
15563                    .buffer_snapshot
15564                    .diff_hunks_in_range(Point::zero()..position)
15565                    .find(|hunk| hunk.row_range.end.0 < position.row)
15566                    .map(|hunk| hunk.row_range.start)
15567            });
15568        }
15569
15570        if let Some(row) = row {
15571            let destination = Point::new(row.0, 0);
15572            let autoscroll = Autoscroll::center();
15573
15574            self.unfold_ranges(&[destination..destination], false, false, cx);
15575            self.change_selections(Some(autoscroll), window, cx, |s| {
15576                s.select_ranges([destination..destination]);
15577            });
15578        }
15579    }
15580
15581    fn do_stage_or_unstage(
15582        &self,
15583        stage: bool,
15584        buffer_id: BufferId,
15585        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
15586        cx: &mut App,
15587    ) -> Option<()> {
15588        let project = self.project.as_ref()?;
15589        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
15590        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
15591        let buffer_snapshot = buffer.read(cx).snapshot();
15592        let file_exists = buffer_snapshot
15593            .file()
15594            .is_some_and(|file| file.disk_state().exists());
15595        diff.update(cx, |diff, cx| {
15596            diff.stage_or_unstage_hunks(
15597                stage,
15598                &hunks
15599                    .map(|hunk| buffer_diff::DiffHunk {
15600                        buffer_range: hunk.buffer_range,
15601                        diff_base_byte_range: hunk.diff_base_byte_range,
15602                        secondary_status: hunk.secondary_status,
15603                        range: Point::zero()..Point::zero(), // unused
15604                    })
15605                    .collect::<Vec<_>>(),
15606                &buffer_snapshot,
15607                file_exists,
15608                cx,
15609            )
15610        });
15611        None
15612    }
15613
15614    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
15615        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15616        self.buffer
15617            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
15618    }
15619
15620    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
15621        self.buffer.update(cx, |buffer, cx| {
15622            let ranges = vec![Anchor::min()..Anchor::max()];
15623            if !buffer.all_diff_hunks_expanded()
15624                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
15625            {
15626                buffer.collapse_diff_hunks(ranges, cx);
15627                true
15628            } else {
15629                false
15630            }
15631        })
15632    }
15633
15634    fn toggle_diff_hunks_in_ranges(
15635        &mut self,
15636        ranges: Vec<Range<Anchor>>,
15637        cx: &mut Context<Editor>,
15638    ) {
15639        self.buffer.update(cx, |buffer, cx| {
15640            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
15641            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
15642        })
15643    }
15644
15645    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
15646        self.buffer.update(cx, |buffer, cx| {
15647            let snapshot = buffer.snapshot(cx);
15648            let excerpt_id = range.end.excerpt_id;
15649            let point_range = range.to_point(&snapshot);
15650            let expand = !buffer.single_hunk_is_expanded(range, cx);
15651            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
15652        })
15653    }
15654
15655    pub(crate) fn apply_all_diff_hunks(
15656        &mut self,
15657        _: &ApplyAllDiffHunks,
15658        window: &mut Window,
15659        cx: &mut Context<Self>,
15660    ) {
15661        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15662
15663        let buffers = self.buffer.read(cx).all_buffers();
15664        for branch_buffer in buffers {
15665            branch_buffer.update(cx, |branch_buffer, cx| {
15666                branch_buffer.merge_into_base(Vec::new(), cx);
15667            });
15668        }
15669
15670        if let Some(project) = self.project.clone() {
15671            self.save(true, project, window, cx).detach_and_log_err(cx);
15672        }
15673    }
15674
15675    pub(crate) fn apply_selected_diff_hunks(
15676        &mut self,
15677        _: &ApplyDiffHunk,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) {
15681        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15682        let snapshot = self.snapshot(window, cx);
15683        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
15684        let mut ranges_by_buffer = HashMap::default();
15685        self.transact(window, cx, |editor, _window, cx| {
15686            for hunk in hunks {
15687                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
15688                    ranges_by_buffer
15689                        .entry(buffer.clone())
15690                        .or_insert_with(Vec::new)
15691                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
15692                }
15693            }
15694
15695            for (buffer, ranges) in ranges_by_buffer {
15696                buffer.update(cx, |buffer, cx| {
15697                    buffer.merge_into_base(ranges, cx);
15698                });
15699            }
15700        });
15701
15702        if let Some(project) = self.project.clone() {
15703            self.save(true, project, window, cx).detach_and_log_err(cx);
15704        }
15705    }
15706
15707    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
15708        if hovered != self.gutter_hovered {
15709            self.gutter_hovered = hovered;
15710            cx.notify();
15711        }
15712    }
15713
15714    pub fn insert_blocks(
15715        &mut self,
15716        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
15717        autoscroll: Option<Autoscroll>,
15718        cx: &mut Context<Self>,
15719    ) -> Vec<CustomBlockId> {
15720        let blocks = self
15721            .display_map
15722            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
15723        if let Some(autoscroll) = autoscroll {
15724            self.request_autoscroll(autoscroll, cx);
15725        }
15726        cx.notify();
15727        blocks
15728    }
15729
15730    pub fn resize_blocks(
15731        &mut self,
15732        heights: HashMap<CustomBlockId, u32>,
15733        autoscroll: Option<Autoscroll>,
15734        cx: &mut Context<Self>,
15735    ) {
15736        self.display_map
15737            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
15738        if let Some(autoscroll) = autoscroll {
15739            self.request_autoscroll(autoscroll, cx);
15740        }
15741        cx.notify();
15742    }
15743
15744    pub fn replace_blocks(
15745        &mut self,
15746        renderers: HashMap<CustomBlockId, RenderBlock>,
15747        autoscroll: Option<Autoscroll>,
15748        cx: &mut Context<Self>,
15749    ) {
15750        self.display_map
15751            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
15752        if let Some(autoscroll) = autoscroll {
15753            self.request_autoscroll(autoscroll, cx);
15754        }
15755        cx.notify();
15756    }
15757
15758    pub fn remove_blocks(
15759        &mut self,
15760        block_ids: HashSet<CustomBlockId>,
15761        autoscroll: Option<Autoscroll>,
15762        cx: &mut Context<Self>,
15763    ) {
15764        self.display_map.update(cx, |display_map, cx| {
15765            display_map.remove_blocks(block_ids, cx)
15766        });
15767        if let Some(autoscroll) = autoscroll {
15768            self.request_autoscroll(autoscroll, cx);
15769        }
15770        cx.notify();
15771    }
15772
15773    pub fn row_for_block(
15774        &self,
15775        block_id: CustomBlockId,
15776        cx: &mut Context<Self>,
15777    ) -> Option<DisplayRow> {
15778        self.display_map
15779            .update(cx, |map, cx| map.row_for_block(block_id, cx))
15780    }
15781
15782    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
15783        self.focused_block = Some(focused_block);
15784    }
15785
15786    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
15787        self.focused_block.take()
15788    }
15789
15790    pub fn insert_creases(
15791        &mut self,
15792        creases: impl IntoIterator<Item = Crease<Anchor>>,
15793        cx: &mut Context<Self>,
15794    ) -> Vec<CreaseId> {
15795        self.display_map
15796            .update(cx, |map, cx| map.insert_creases(creases, cx))
15797    }
15798
15799    pub fn remove_creases(
15800        &mut self,
15801        ids: impl IntoIterator<Item = CreaseId>,
15802        cx: &mut Context<Self>,
15803    ) {
15804        self.display_map
15805            .update(cx, |map, cx| map.remove_creases(ids, cx));
15806    }
15807
15808    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
15809        self.display_map
15810            .update(cx, |map, cx| map.snapshot(cx))
15811            .longest_row()
15812    }
15813
15814    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
15815        self.display_map
15816            .update(cx, |map, cx| map.snapshot(cx))
15817            .max_point()
15818    }
15819
15820    pub fn text(&self, cx: &App) -> String {
15821        self.buffer.read(cx).read(cx).text()
15822    }
15823
15824    pub fn is_empty(&self, cx: &App) -> bool {
15825        self.buffer.read(cx).read(cx).is_empty()
15826    }
15827
15828    pub fn text_option(&self, cx: &App) -> Option<String> {
15829        let text = self.text(cx);
15830        let text = text.trim();
15831
15832        if text.is_empty() {
15833            return None;
15834        }
15835
15836        Some(text.to_string())
15837    }
15838
15839    pub fn set_text(
15840        &mut self,
15841        text: impl Into<Arc<str>>,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) {
15845        self.transact(window, cx, |this, _, cx| {
15846            this.buffer
15847                .read(cx)
15848                .as_singleton()
15849                .expect("you can only call set_text on editors for singleton buffers")
15850                .update(cx, |buffer, cx| buffer.set_text(text, cx));
15851        });
15852    }
15853
15854    pub fn display_text(&self, cx: &mut App) -> String {
15855        self.display_map
15856            .update(cx, |map, cx| map.snapshot(cx))
15857            .text()
15858    }
15859
15860    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
15861        let mut wrap_guides = smallvec::smallvec![];
15862
15863        if self.show_wrap_guides == Some(false) {
15864            return wrap_guides;
15865        }
15866
15867        let settings = self.buffer.read(cx).language_settings(cx);
15868        if settings.show_wrap_guides {
15869            match self.soft_wrap_mode(cx) {
15870                SoftWrap::Column(soft_wrap) => {
15871                    wrap_guides.push((soft_wrap as usize, true));
15872                }
15873                SoftWrap::Bounded(soft_wrap) => {
15874                    wrap_guides.push((soft_wrap as usize, true));
15875                }
15876                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
15877            }
15878            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
15879        }
15880
15881        wrap_guides
15882    }
15883
15884    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
15885        let settings = self.buffer.read(cx).language_settings(cx);
15886        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
15887        match mode {
15888            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
15889                SoftWrap::None
15890            }
15891            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
15892            language_settings::SoftWrap::PreferredLineLength => {
15893                SoftWrap::Column(settings.preferred_line_length)
15894            }
15895            language_settings::SoftWrap::Bounded => {
15896                SoftWrap::Bounded(settings.preferred_line_length)
15897            }
15898        }
15899    }
15900
15901    pub fn set_soft_wrap_mode(
15902        &mut self,
15903        mode: language_settings::SoftWrap,
15904
15905        cx: &mut Context<Self>,
15906    ) {
15907        self.soft_wrap_mode_override = Some(mode);
15908        cx.notify();
15909    }
15910
15911    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
15912        self.hard_wrap = hard_wrap;
15913        cx.notify();
15914    }
15915
15916    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
15917        self.text_style_refinement = Some(style);
15918    }
15919
15920    /// called by the Element so we know what style we were most recently rendered with.
15921    pub(crate) fn set_style(
15922        &mut self,
15923        style: EditorStyle,
15924        window: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) {
15927        let rem_size = window.rem_size();
15928        self.display_map.update(cx, |map, cx| {
15929            map.set_font(
15930                style.text.font(),
15931                style.text.font_size.to_pixels(rem_size),
15932                cx,
15933            )
15934        });
15935        self.style = Some(style);
15936    }
15937
15938    pub fn style(&self) -> Option<&EditorStyle> {
15939        self.style.as_ref()
15940    }
15941
15942    // Called by the element. This method is not designed to be called outside of the editor
15943    // element's layout code because it does not notify when rewrapping is computed synchronously.
15944    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
15945        self.display_map
15946            .update(cx, |map, cx| map.set_wrap_width(width, cx))
15947    }
15948
15949    pub fn set_soft_wrap(&mut self) {
15950        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
15951    }
15952
15953    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
15954        if self.soft_wrap_mode_override.is_some() {
15955            self.soft_wrap_mode_override.take();
15956        } else {
15957            let soft_wrap = match self.soft_wrap_mode(cx) {
15958                SoftWrap::GitDiff => return,
15959                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
15960                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
15961                    language_settings::SoftWrap::None
15962                }
15963            };
15964            self.soft_wrap_mode_override = Some(soft_wrap);
15965        }
15966        cx.notify();
15967    }
15968
15969    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
15970        let Some(workspace) = self.workspace() else {
15971            return;
15972        };
15973        let fs = workspace.read(cx).app_state().fs.clone();
15974        let current_show = TabBarSettings::get_global(cx).show;
15975        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
15976            setting.show = Some(!current_show);
15977        });
15978    }
15979
15980    pub fn toggle_indent_guides(
15981        &mut self,
15982        _: &ToggleIndentGuides,
15983        _: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
15987            self.buffer
15988                .read(cx)
15989                .language_settings(cx)
15990                .indent_guides
15991                .enabled
15992        });
15993        self.show_indent_guides = Some(!currently_enabled);
15994        cx.notify();
15995    }
15996
15997    fn should_show_indent_guides(&self) -> Option<bool> {
15998        self.show_indent_guides
15999    }
16000
16001    pub fn toggle_line_numbers(
16002        &mut self,
16003        _: &ToggleLineNumbers,
16004        _: &mut Window,
16005        cx: &mut Context<Self>,
16006    ) {
16007        let mut editor_settings = EditorSettings::get_global(cx).clone();
16008        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16009        EditorSettings::override_global(editor_settings, cx);
16010    }
16011
16012    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16013        if let Some(show_line_numbers) = self.show_line_numbers {
16014            return show_line_numbers;
16015        }
16016        EditorSettings::get_global(cx).gutter.line_numbers
16017    }
16018
16019    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16020        self.use_relative_line_numbers
16021            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16022    }
16023
16024    pub fn toggle_relative_line_numbers(
16025        &mut self,
16026        _: &ToggleRelativeLineNumbers,
16027        _: &mut Window,
16028        cx: &mut Context<Self>,
16029    ) {
16030        let is_relative = self.should_use_relative_line_numbers(cx);
16031        self.set_relative_line_number(Some(!is_relative), cx)
16032    }
16033
16034    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16035        self.use_relative_line_numbers = is_relative;
16036        cx.notify();
16037    }
16038
16039    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16040        self.show_gutter = show_gutter;
16041        cx.notify();
16042    }
16043
16044    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16045        self.show_scrollbars = show_scrollbars;
16046        cx.notify();
16047    }
16048
16049    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16050        self.show_line_numbers = Some(show_line_numbers);
16051        cx.notify();
16052    }
16053
16054    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16055        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16056        cx.notify();
16057    }
16058
16059    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16060        self.show_code_actions = Some(show_code_actions);
16061        cx.notify();
16062    }
16063
16064    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16065        self.show_runnables = Some(show_runnables);
16066        cx.notify();
16067    }
16068
16069    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16070        self.show_breakpoints = Some(show_breakpoints);
16071        cx.notify();
16072    }
16073
16074    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16075        if self.display_map.read(cx).masked != masked {
16076            self.display_map.update(cx, |map, _| map.masked = masked);
16077        }
16078        cx.notify()
16079    }
16080
16081    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16082        self.show_wrap_guides = Some(show_wrap_guides);
16083        cx.notify();
16084    }
16085
16086    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16087        self.show_indent_guides = Some(show_indent_guides);
16088        cx.notify();
16089    }
16090
16091    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16092        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16093            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16094                if let Some(dir) = file.abs_path(cx).parent() {
16095                    return Some(dir.to_owned());
16096                }
16097            }
16098
16099            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16100                return Some(project_path.path.to_path_buf());
16101            }
16102        }
16103
16104        None
16105    }
16106
16107    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16108        self.active_excerpt(cx)?
16109            .1
16110            .read(cx)
16111            .file()
16112            .and_then(|f| f.as_local())
16113    }
16114
16115    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16116        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16117            let buffer = buffer.read(cx);
16118            if let Some(project_path) = buffer.project_path(cx) {
16119                let project = self.project.as_ref()?.read(cx);
16120                project.absolute_path(&project_path, cx)
16121            } else {
16122                buffer
16123                    .file()
16124                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16125            }
16126        })
16127    }
16128
16129    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16130        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16131            let project_path = buffer.read(cx).project_path(cx)?;
16132            let project = self.project.as_ref()?.read(cx);
16133            let entry = project.entry_for_path(&project_path, cx)?;
16134            let path = entry.path.to_path_buf();
16135            Some(path)
16136        })
16137    }
16138
16139    pub fn reveal_in_finder(
16140        &mut self,
16141        _: &RevealInFileManager,
16142        _window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) {
16145        if let Some(target) = self.target_file(cx) {
16146            cx.reveal_path(&target.abs_path(cx));
16147        }
16148    }
16149
16150    pub fn copy_path(
16151        &mut self,
16152        _: &zed_actions::workspace::CopyPath,
16153        _window: &mut Window,
16154        cx: &mut Context<Self>,
16155    ) {
16156        if let Some(path) = self.target_file_abs_path(cx) {
16157            if let Some(path) = path.to_str() {
16158                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16159            }
16160        }
16161    }
16162
16163    pub fn copy_relative_path(
16164        &mut self,
16165        _: &zed_actions::workspace::CopyRelativePath,
16166        _window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) {
16169        if let Some(path) = self.target_file_path(cx) {
16170            if let Some(path) = path.to_str() {
16171                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16172            }
16173        }
16174    }
16175
16176    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16177        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16178            buffer.read(cx).project_path(cx)
16179        } else {
16180            None
16181        }
16182    }
16183
16184    // Returns true if the editor handled a go-to-line request
16185    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
16186        maybe!({
16187            let breakpoint_store = self.breakpoint_store.as_ref()?;
16188
16189            let Some((_, _, active_position)) =
16190                breakpoint_store.read(cx).active_position().cloned()
16191            else {
16192                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16193                return None;
16194            };
16195
16196            let snapshot = self
16197                .project
16198                .as_ref()?
16199                .read(cx)
16200                .buffer_for_id(active_position.buffer_id?, cx)?
16201                .read(cx)
16202                .snapshot();
16203
16204            let mut handled = false;
16205            for (id, ExcerptRange { context, .. }) in self
16206                .buffer
16207                .read(cx)
16208                .excerpts_for_buffer(active_position.buffer_id?, cx)
16209            {
16210                if context.start.cmp(&active_position, &snapshot).is_ge()
16211                    || context.end.cmp(&active_position, &snapshot).is_lt()
16212                {
16213                    continue;
16214                }
16215                let snapshot = self.buffer.read(cx).snapshot(cx);
16216                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, active_position)?;
16217
16218                handled = true;
16219                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16220                self.go_to_line::<DebugCurrentRowHighlight>(
16221                    multibuffer_anchor,
16222                    Some(cx.theme().colors().editor_debugger_active_line_background),
16223                    window,
16224                    cx,
16225                );
16226
16227                cx.notify();
16228            }
16229            handled.then_some(())
16230        })
16231        .is_some()
16232    }
16233
16234    pub fn copy_file_name_without_extension(
16235        &mut self,
16236        _: &CopyFileNameWithoutExtension,
16237        _: &mut Window,
16238        cx: &mut Context<Self>,
16239    ) {
16240        if let Some(file) = self.target_file(cx) {
16241            if let Some(file_stem) = file.path().file_stem() {
16242                if let Some(name) = file_stem.to_str() {
16243                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16244                }
16245            }
16246        }
16247    }
16248
16249    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
16250        if let Some(file) = self.target_file(cx) {
16251            if let Some(file_name) = file.path().file_name() {
16252                if let Some(name) = file_name.to_str() {
16253                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16254                }
16255            }
16256        }
16257    }
16258
16259    pub fn toggle_git_blame(
16260        &mut self,
16261        _: &::git::Blame,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) {
16265        self.show_git_blame_gutter = !self.show_git_blame_gutter;
16266
16267        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
16268            self.start_git_blame(true, window, cx);
16269        }
16270
16271        cx.notify();
16272    }
16273
16274    pub fn toggle_git_blame_inline(
16275        &mut self,
16276        _: &ToggleGitBlameInline,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        self.toggle_git_blame_inline_internal(true, window, cx);
16281        cx.notify();
16282    }
16283
16284    pub fn open_git_blame_commit(
16285        &mut self,
16286        _: &OpenGitBlameCommit,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) {
16290        self.open_git_blame_commit_internal(window, cx);
16291    }
16292
16293    fn open_git_blame_commit_internal(
16294        &mut self,
16295        window: &mut Window,
16296        cx: &mut Context<Self>,
16297    ) -> Option<()> {
16298        let blame = self.blame.as_ref()?;
16299        let snapshot = self.snapshot(window, cx);
16300        let cursor = self.selections.newest::<Point>(cx).head();
16301        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
16302        let blame_entry = blame
16303            .update(cx, |blame, cx| {
16304                blame
16305                    .blame_for_rows(
16306                        &[RowInfo {
16307                            buffer_id: Some(buffer.remote_id()),
16308                            buffer_row: Some(point.row),
16309                            ..Default::default()
16310                        }],
16311                        cx,
16312                    )
16313                    .next()
16314            })
16315            .flatten()?;
16316        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
16317        let repo = blame.read(cx).repository(cx)?;
16318        let workspace = self.workspace()?.downgrade();
16319        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
16320        None
16321    }
16322
16323    pub fn git_blame_inline_enabled(&self) -> bool {
16324        self.git_blame_inline_enabled
16325    }
16326
16327    pub fn toggle_selection_menu(
16328        &mut self,
16329        _: &ToggleSelectionMenu,
16330        _: &mut Window,
16331        cx: &mut Context<Self>,
16332    ) {
16333        self.show_selection_menu = self
16334            .show_selection_menu
16335            .map(|show_selections_menu| !show_selections_menu)
16336            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
16337
16338        cx.notify();
16339    }
16340
16341    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
16342        self.show_selection_menu
16343            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
16344    }
16345
16346    fn start_git_blame(
16347        &mut self,
16348        user_triggered: bool,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) {
16352        if let Some(project) = self.project.as_ref() {
16353            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
16354                return;
16355            };
16356
16357            if buffer.read(cx).file().is_none() {
16358                return;
16359            }
16360
16361            let focused = self.focus_handle(cx).contains_focused(window, cx);
16362
16363            let project = project.clone();
16364            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
16365            self.blame_subscription =
16366                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
16367            self.blame = Some(blame);
16368        }
16369    }
16370
16371    fn toggle_git_blame_inline_internal(
16372        &mut self,
16373        user_triggered: bool,
16374        window: &mut Window,
16375        cx: &mut Context<Self>,
16376    ) {
16377        if self.git_blame_inline_enabled {
16378            self.git_blame_inline_enabled = false;
16379            self.show_git_blame_inline = false;
16380            self.show_git_blame_inline_delay_task.take();
16381        } else {
16382            self.git_blame_inline_enabled = true;
16383            self.start_git_blame_inline(user_triggered, window, cx);
16384        }
16385
16386        cx.notify();
16387    }
16388
16389    fn start_git_blame_inline(
16390        &mut self,
16391        user_triggered: bool,
16392        window: &mut Window,
16393        cx: &mut Context<Self>,
16394    ) {
16395        self.start_git_blame(user_triggered, window, cx);
16396
16397        if ProjectSettings::get_global(cx)
16398            .git
16399            .inline_blame_delay()
16400            .is_some()
16401        {
16402            self.start_inline_blame_timer(window, cx);
16403        } else {
16404            self.show_git_blame_inline = true
16405        }
16406    }
16407
16408    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
16409        self.blame.as_ref()
16410    }
16411
16412    pub fn show_git_blame_gutter(&self) -> bool {
16413        self.show_git_blame_gutter
16414    }
16415
16416    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
16417        self.show_git_blame_gutter && self.has_blame_entries(cx)
16418    }
16419
16420    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
16421        self.show_git_blame_inline
16422            && (self.focus_handle.is_focused(window)
16423                || self
16424                    .git_blame_inline_tooltip
16425                    .as_ref()
16426                    .and_then(|t| t.upgrade())
16427                    .is_some())
16428            && !self.newest_selection_head_on_empty_line(cx)
16429            && self.has_blame_entries(cx)
16430    }
16431
16432    fn has_blame_entries(&self, cx: &App) -> bool {
16433        self.blame()
16434            .map_or(false, |blame| blame.read(cx).has_generated_entries())
16435    }
16436
16437    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
16438        let cursor_anchor = self.selections.newest_anchor().head();
16439
16440        let snapshot = self.buffer.read(cx).snapshot(cx);
16441        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
16442
16443        snapshot.line_len(buffer_row) == 0
16444    }
16445
16446    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
16447        let buffer_and_selection = maybe!({
16448            let selection = self.selections.newest::<Point>(cx);
16449            let selection_range = selection.range();
16450
16451            let multi_buffer = self.buffer().read(cx);
16452            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16453            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
16454
16455            let (buffer, range, _) = if selection.reversed {
16456                buffer_ranges.first()
16457            } else {
16458                buffer_ranges.last()
16459            }?;
16460
16461            let selection = text::ToPoint::to_point(&range.start, &buffer).row
16462                ..text::ToPoint::to_point(&range.end, &buffer).row;
16463            Some((
16464                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
16465                selection,
16466            ))
16467        });
16468
16469        let Some((buffer, selection)) = buffer_and_selection else {
16470            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
16471        };
16472
16473        let Some(project) = self.project.as_ref() else {
16474            return Task::ready(Err(anyhow!("editor does not have project")));
16475        };
16476
16477        project.update(cx, |project, cx| {
16478            project.get_permalink_to_line(&buffer, selection, cx)
16479        })
16480    }
16481
16482    pub fn copy_permalink_to_line(
16483        &mut self,
16484        _: &CopyPermalinkToLine,
16485        window: &mut Window,
16486        cx: &mut Context<Self>,
16487    ) {
16488        let permalink_task = self.get_permalink_to_line(cx);
16489        let workspace = self.workspace();
16490
16491        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16492            Ok(permalink) => {
16493                cx.update(|_, cx| {
16494                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
16495                })
16496                .ok();
16497            }
16498            Err(err) => {
16499                let message = format!("Failed to copy permalink: {err}");
16500
16501                Err::<(), anyhow::Error>(err).log_err();
16502
16503                if let Some(workspace) = workspace {
16504                    workspace
16505                        .update_in(cx, |workspace, _, cx| {
16506                            struct CopyPermalinkToLine;
16507
16508                            workspace.show_toast(
16509                                Toast::new(
16510                                    NotificationId::unique::<CopyPermalinkToLine>(),
16511                                    message,
16512                                ),
16513                                cx,
16514                            )
16515                        })
16516                        .ok();
16517                }
16518            }
16519        })
16520        .detach();
16521    }
16522
16523    pub fn copy_file_location(
16524        &mut self,
16525        _: &CopyFileLocation,
16526        _: &mut Window,
16527        cx: &mut Context<Self>,
16528    ) {
16529        let selection = self.selections.newest::<Point>(cx).start.row + 1;
16530        if let Some(file) = self.target_file(cx) {
16531            if let Some(path) = file.path().to_str() {
16532                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
16533            }
16534        }
16535    }
16536
16537    pub fn open_permalink_to_line(
16538        &mut self,
16539        _: &OpenPermalinkToLine,
16540        window: &mut Window,
16541        cx: &mut Context<Self>,
16542    ) {
16543        let permalink_task = self.get_permalink_to_line(cx);
16544        let workspace = self.workspace();
16545
16546        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16547            Ok(permalink) => {
16548                cx.update(|_, cx| {
16549                    cx.open_url(permalink.as_ref());
16550                })
16551                .ok();
16552            }
16553            Err(err) => {
16554                let message = format!("Failed to open permalink: {err}");
16555
16556                Err::<(), anyhow::Error>(err).log_err();
16557
16558                if let Some(workspace) = workspace {
16559                    workspace
16560                        .update(cx, |workspace, cx| {
16561                            struct OpenPermalinkToLine;
16562
16563                            workspace.show_toast(
16564                                Toast::new(
16565                                    NotificationId::unique::<OpenPermalinkToLine>(),
16566                                    message,
16567                                ),
16568                                cx,
16569                            )
16570                        })
16571                        .ok();
16572                }
16573            }
16574        })
16575        .detach();
16576    }
16577
16578    pub fn insert_uuid_v4(
16579        &mut self,
16580        _: &InsertUuidV4,
16581        window: &mut Window,
16582        cx: &mut Context<Self>,
16583    ) {
16584        self.insert_uuid(UuidVersion::V4, window, cx);
16585    }
16586
16587    pub fn insert_uuid_v7(
16588        &mut self,
16589        _: &InsertUuidV7,
16590        window: &mut Window,
16591        cx: &mut Context<Self>,
16592    ) {
16593        self.insert_uuid(UuidVersion::V7, window, cx);
16594    }
16595
16596    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
16597        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16598        self.transact(window, cx, |this, window, cx| {
16599            let edits = this
16600                .selections
16601                .all::<Point>(cx)
16602                .into_iter()
16603                .map(|selection| {
16604                    let uuid = match version {
16605                        UuidVersion::V4 => uuid::Uuid::new_v4(),
16606                        UuidVersion::V7 => uuid::Uuid::now_v7(),
16607                    };
16608
16609                    (selection.range(), uuid.to_string())
16610                });
16611            this.edit(edits, cx);
16612            this.refresh_inline_completion(true, false, window, cx);
16613        });
16614    }
16615
16616    pub fn open_selections_in_multibuffer(
16617        &mut self,
16618        _: &OpenSelectionsInMultibuffer,
16619        window: &mut Window,
16620        cx: &mut Context<Self>,
16621    ) {
16622        let multibuffer = self.buffer.read(cx);
16623
16624        let Some(buffer) = multibuffer.as_singleton() else {
16625            return;
16626        };
16627
16628        let Some(workspace) = self.workspace() else {
16629            return;
16630        };
16631
16632        let locations = self
16633            .selections
16634            .disjoint_anchors()
16635            .iter()
16636            .map(|range| Location {
16637                buffer: buffer.clone(),
16638                range: range.start.text_anchor..range.end.text_anchor,
16639            })
16640            .collect::<Vec<_>>();
16641
16642        let title = multibuffer.title(cx).to_string();
16643
16644        cx.spawn_in(window, async move |_, cx| {
16645            workspace.update_in(cx, |workspace, window, cx| {
16646                Self::open_locations_in_multibuffer(
16647                    workspace,
16648                    locations,
16649                    format!("Selections for '{title}'"),
16650                    false,
16651                    MultibufferSelectionMode::All,
16652                    window,
16653                    cx,
16654                );
16655            })
16656        })
16657        .detach();
16658    }
16659
16660    /// Adds a row highlight for the given range. If a row has multiple highlights, the
16661    /// last highlight added will be used.
16662    ///
16663    /// If the range ends at the beginning of a line, then that line will not be highlighted.
16664    pub fn highlight_rows<T: 'static>(
16665        &mut self,
16666        range: Range<Anchor>,
16667        color: Hsla,
16668        should_autoscroll: bool,
16669        cx: &mut Context<Self>,
16670    ) {
16671        let snapshot = self.buffer().read(cx).snapshot(cx);
16672        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16673        let ix = row_highlights.binary_search_by(|highlight| {
16674            Ordering::Equal
16675                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
16676                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
16677        });
16678
16679        if let Err(mut ix) = ix {
16680            let index = post_inc(&mut self.highlight_order);
16681
16682            // If this range intersects with the preceding highlight, then merge it with
16683            // the preceding highlight. Otherwise insert a new highlight.
16684            let mut merged = false;
16685            if ix > 0 {
16686                let prev_highlight = &mut row_highlights[ix - 1];
16687                if prev_highlight
16688                    .range
16689                    .end
16690                    .cmp(&range.start, &snapshot)
16691                    .is_ge()
16692                {
16693                    ix -= 1;
16694                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
16695                        prev_highlight.range.end = range.end;
16696                    }
16697                    merged = true;
16698                    prev_highlight.index = index;
16699                    prev_highlight.color = color;
16700                    prev_highlight.should_autoscroll = should_autoscroll;
16701                }
16702            }
16703
16704            if !merged {
16705                row_highlights.insert(
16706                    ix,
16707                    RowHighlight {
16708                        range: range.clone(),
16709                        index,
16710                        color,
16711                        should_autoscroll,
16712                    },
16713                );
16714            }
16715
16716            // If any of the following highlights intersect with this one, merge them.
16717            while let Some(next_highlight) = row_highlights.get(ix + 1) {
16718                let highlight = &row_highlights[ix];
16719                if next_highlight
16720                    .range
16721                    .start
16722                    .cmp(&highlight.range.end, &snapshot)
16723                    .is_le()
16724                {
16725                    if next_highlight
16726                        .range
16727                        .end
16728                        .cmp(&highlight.range.end, &snapshot)
16729                        .is_gt()
16730                    {
16731                        row_highlights[ix].range.end = next_highlight.range.end;
16732                    }
16733                    row_highlights.remove(ix + 1);
16734                } else {
16735                    break;
16736                }
16737            }
16738        }
16739    }
16740
16741    /// Remove any highlighted row ranges of the given type that intersect the
16742    /// given ranges.
16743    pub fn remove_highlighted_rows<T: 'static>(
16744        &mut self,
16745        ranges_to_remove: Vec<Range<Anchor>>,
16746        cx: &mut Context<Self>,
16747    ) {
16748        let snapshot = self.buffer().read(cx).snapshot(cx);
16749        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16750        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
16751        row_highlights.retain(|highlight| {
16752            while let Some(range_to_remove) = ranges_to_remove.peek() {
16753                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
16754                    Ordering::Less | Ordering::Equal => {
16755                        ranges_to_remove.next();
16756                    }
16757                    Ordering::Greater => {
16758                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
16759                            Ordering::Less | Ordering::Equal => {
16760                                return false;
16761                            }
16762                            Ordering::Greater => break,
16763                        }
16764                    }
16765                }
16766            }
16767
16768            true
16769        })
16770    }
16771
16772    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
16773    pub fn clear_row_highlights<T: 'static>(&mut self) {
16774        self.highlighted_rows.remove(&TypeId::of::<T>());
16775    }
16776
16777    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
16778    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
16779        self.highlighted_rows
16780            .get(&TypeId::of::<T>())
16781            .map_or(&[] as &[_], |vec| vec.as_slice())
16782            .iter()
16783            .map(|highlight| (highlight.range.clone(), highlight.color))
16784    }
16785
16786    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
16787    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
16788    /// Allows to ignore certain kinds of highlights.
16789    pub fn highlighted_display_rows(
16790        &self,
16791        window: &mut Window,
16792        cx: &mut App,
16793    ) -> BTreeMap<DisplayRow, LineHighlight> {
16794        let snapshot = self.snapshot(window, cx);
16795        let mut used_highlight_orders = HashMap::default();
16796        self.highlighted_rows
16797            .iter()
16798            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
16799            .fold(
16800                BTreeMap::<DisplayRow, LineHighlight>::new(),
16801                |mut unique_rows, highlight| {
16802                    let start = highlight.range.start.to_display_point(&snapshot);
16803                    let end = highlight.range.end.to_display_point(&snapshot);
16804                    let start_row = start.row().0;
16805                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
16806                        && end.column() == 0
16807                    {
16808                        end.row().0.saturating_sub(1)
16809                    } else {
16810                        end.row().0
16811                    };
16812                    for row in start_row..=end_row {
16813                        let used_index =
16814                            used_highlight_orders.entry(row).or_insert(highlight.index);
16815                        if highlight.index >= *used_index {
16816                            *used_index = highlight.index;
16817                            unique_rows.insert(DisplayRow(row), highlight.color.into());
16818                        }
16819                    }
16820                    unique_rows
16821                },
16822            )
16823    }
16824
16825    pub fn highlighted_display_row_for_autoscroll(
16826        &self,
16827        snapshot: &DisplaySnapshot,
16828    ) -> Option<DisplayRow> {
16829        self.highlighted_rows
16830            .values()
16831            .flat_map(|highlighted_rows| highlighted_rows.iter())
16832            .filter_map(|highlight| {
16833                if highlight.should_autoscroll {
16834                    Some(highlight.range.start.to_display_point(snapshot).row())
16835                } else {
16836                    None
16837                }
16838            })
16839            .min()
16840    }
16841
16842    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
16843        self.highlight_background::<SearchWithinRange>(
16844            ranges,
16845            |colors| colors.editor_document_highlight_read_background,
16846            cx,
16847        )
16848    }
16849
16850    pub fn set_breadcrumb_header(&mut self, new_header: String) {
16851        self.breadcrumb_header = Some(new_header);
16852    }
16853
16854    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
16855        self.clear_background_highlights::<SearchWithinRange>(cx);
16856    }
16857
16858    pub fn highlight_background<T: 'static>(
16859        &mut self,
16860        ranges: &[Range<Anchor>],
16861        color_fetcher: fn(&ThemeColors) -> Hsla,
16862        cx: &mut Context<Self>,
16863    ) {
16864        self.background_highlights
16865            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
16866        self.scrollbar_marker_state.dirty = true;
16867        cx.notify();
16868    }
16869
16870    pub fn clear_background_highlights<T: 'static>(
16871        &mut self,
16872        cx: &mut Context<Self>,
16873    ) -> Option<BackgroundHighlight> {
16874        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
16875        if !text_highlights.1.is_empty() {
16876            self.scrollbar_marker_state.dirty = true;
16877            cx.notify();
16878        }
16879        Some(text_highlights)
16880    }
16881
16882    pub fn highlight_gutter<T: 'static>(
16883        &mut self,
16884        ranges: &[Range<Anchor>],
16885        color_fetcher: fn(&App) -> Hsla,
16886        cx: &mut Context<Self>,
16887    ) {
16888        self.gutter_highlights
16889            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
16890        cx.notify();
16891    }
16892
16893    pub fn clear_gutter_highlights<T: 'static>(
16894        &mut self,
16895        cx: &mut Context<Self>,
16896    ) -> Option<GutterHighlight> {
16897        cx.notify();
16898        self.gutter_highlights.remove(&TypeId::of::<T>())
16899    }
16900
16901    #[cfg(feature = "test-support")]
16902    pub fn all_text_background_highlights(
16903        &self,
16904        window: &mut Window,
16905        cx: &mut Context<Self>,
16906    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
16907        let snapshot = self.snapshot(window, cx);
16908        let buffer = &snapshot.buffer_snapshot;
16909        let start = buffer.anchor_before(0);
16910        let end = buffer.anchor_after(buffer.len());
16911        let theme = cx.theme().colors();
16912        self.background_highlights_in_range(start..end, &snapshot, theme)
16913    }
16914
16915    #[cfg(feature = "test-support")]
16916    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
16917        let snapshot = self.buffer().read(cx).snapshot(cx);
16918
16919        let highlights = self
16920            .background_highlights
16921            .get(&TypeId::of::<items::BufferSearchHighlights>());
16922
16923        if let Some((_color, ranges)) = highlights {
16924            ranges
16925                .iter()
16926                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
16927                .collect_vec()
16928        } else {
16929            vec![]
16930        }
16931    }
16932
16933    fn document_highlights_for_position<'a>(
16934        &'a self,
16935        position: Anchor,
16936        buffer: &'a MultiBufferSnapshot,
16937    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
16938        let read_highlights = self
16939            .background_highlights
16940            .get(&TypeId::of::<DocumentHighlightRead>())
16941            .map(|h| &h.1);
16942        let write_highlights = self
16943            .background_highlights
16944            .get(&TypeId::of::<DocumentHighlightWrite>())
16945            .map(|h| &h.1);
16946        let left_position = position.bias_left(buffer);
16947        let right_position = position.bias_right(buffer);
16948        read_highlights
16949            .into_iter()
16950            .chain(write_highlights)
16951            .flat_map(move |ranges| {
16952                let start_ix = match ranges.binary_search_by(|probe| {
16953                    let cmp = probe.end.cmp(&left_position, buffer);
16954                    if cmp.is_ge() {
16955                        Ordering::Greater
16956                    } else {
16957                        Ordering::Less
16958                    }
16959                }) {
16960                    Ok(i) | Err(i) => i,
16961                };
16962
16963                ranges[start_ix..]
16964                    .iter()
16965                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
16966            })
16967    }
16968
16969    pub fn has_background_highlights<T: 'static>(&self) -> bool {
16970        self.background_highlights
16971            .get(&TypeId::of::<T>())
16972            .map_or(false, |(_, highlights)| !highlights.is_empty())
16973    }
16974
16975    pub fn background_highlights_in_range(
16976        &self,
16977        search_range: Range<Anchor>,
16978        display_snapshot: &DisplaySnapshot,
16979        theme: &ThemeColors,
16980    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
16981        let mut results = Vec::new();
16982        for (color_fetcher, ranges) in self.background_highlights.values() {
16983            let color = color_fetcher(theme);
16984            let start_ix = match ranges.binary_search_by(|probe| {
16985                let cmp = probe
16986                    .end
16987                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
16988                if cmp.is_gt() {
16989                    Ordering::Greater
16990                } else {
16991                    Ordering::Less
16992                }
16993            }) {
16994                Ok(i) | Err(i) => i,
16995            };
16996            for range in &ranges[start_ix..] {
16997                if range
16998                    .start
16999                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17000                    .is_ge()
17001                {
17002                    break;
17003                }
17004
17005                let start = range.start.to_display_point(display_snapshot);
17006                let end = range.end.to_display_point(display_snapshot);
17007                results.push((start..end, color))
17008            }
17009        }
17010        results
17011    }
17012
17013    pub fn background_highlight_row_ranges<T: 'static>(
17014        &self,
17015        search_range: Range<Anchor>,
17016        display_snapshot: &DisplaySnapshot,
17017        count: usize,
17018    ) -> Vec<RangeInclusive<DisplayPoint>> {
17019        let mut results = Vec::new();
17020        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17021            return vec![];
17022        };
17023
17024        let start_ix = match ranges.binary_search_by(|probe| {
17025            let cmp = probe
17026                .end
17027                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17028            if cmp.is_gt() {
17029                Ordering::Greater
17030            } else {
17031                Ordering::Less
17032            }
17033        }) {
17034            Ok(i) | Err(i) => i,
17035        };
17036        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17037            if let (Some(start_display), Some(end_display)) = (start, end) {
17038                results.push(
17039                    start_display.to_display_point(display_snapshot)
17040                        ..=end_display.to_display_point(display_snapshot),
17041                );
17042            }
17043        };
17044        let mut start_row: Option<Point> = None;
17045        let mut end_row: Option<Point> = None;
17046        if ranges.len() > count {
17047            return Vec::new();
17048        }
17049        for range in &ranges[start_ix..] {
17050            if range
17051                .start
17052                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17053                .is_ge()
17054            {
17055                break;
17056            }
17057            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17058            if let Some(current_row) = &end_row {
17059                if end.row == current_row.row {
17060                    continue;
17061                }
17062            }
17063            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17064            if start_row.is_none() {
17065                assert_eq!(end_row, None);
17066                start_row = Some(start);
17067                end_row = Some(end);
17068                continue;
17069            }
17070            if let Some(current_end) = end_row.as_mut() {
17071                if start.row > current_end.row + 1 {
17072                    push_region(start_row, end_row);
17073                    start_row = Some(start);
17074                    end_row = Some(end);
17075                } else {
17076                    // Merge two hunks.
17077                    *current_end = end;
17078                }
17079            } else {
17080                unreachable!();
17081            }
17082        }
17083        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17084        push_region(start_row, end_row);
17085        results
17086    }
17087
17088    pub fn gutter_highlights_in_range(
17089        &self,
17090        search_range: Range<Anchor>,
17091        display_snapshot: &DisplaySnapshot,
17092        cx: &App,
17093    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17094        let mut results = Vec::new();
17095        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17096            let color = color_fetcher(cx);
17097            let start_ix = match ranges.binary_search_by(|probe| {
17098                let cmp = probe
17099                    .end
17100                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17101                if cmp.is_gt() {
17102                    Ordering::Greater
17103                } else {
17104                    Ordering::Less
17105                }
17106            }) {
17107                Ok(i) | Err(i) => i,
17108            };
17109            for range in &ranges[start_ix..] {
17110                if range
17111                    .start
17112                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17113                    .is_ge()
17114                {
17115                    break;
17116                }
17117
17118                let start = range.start.to_display_point(display_snapshot);
17119                let end = range.end.to_display_point(display_snapshot);
17120                results.push((start..end, color))
17121            }
17122        }
17123        results
17124    }
17125
17126    /// Get the text ranges corresponding to the redaction query
17127    pub fn redacted_ranges(
17128        &self,
17129        search_range: Range<Anchor>,
17130        display_snapshot: &DisplaySnapshot,
17131        cx: &App,
17132    ) -> Vec<Range<DisplayPoint>> {
17133        display_snapshot
17134            .buffer_snapshot
17135            .redacted_ranges(search_range, |file| {
17136                if let Some(file) = file {
17137                    file.is_private()
17138                        && EditorSettings::get(
17139                            Some(SettingsLocation {
17140                                worktree_id: file.worktree_id(cx),
17141                                path: file.path().as_ref(),
17142                            }),
17143                            cx,
17144                        )
17145                        .redact_private_values
17146                } else {
17147                    false
17148                }
17149            })
17150            .map(|range| {
17151                range.start.to_display_point(display_snapshot)
17152                    ..range.end.to_display_point(display_snapshot)
17153            })
17154            .collect()
17155    }
17156
17157    pub fn highlight_text<T: 'static>(
17158        &mut self,
17159        ranges: Vec<Range<Anchor>>,
17160        style: HighlightStyle,
17161        cx: &mut Context<Self>,
17162    ) {
17163        self.display_map.update(cx, |map, _| {
17164            map.highlight_text(TypeId::of::<T>(), ranges, style)
17165        });
17166        cx.notify();
17167    }
17168
17169    pub(crate) fn highlight_inlays<T: 'static>(
17170        &mut self,
17171        highlights: Vec<InlayHighlight>,
17172        style: HighlightStyle,
17173        cx: &mut Context<Self>,
17174    ) {
17175        self.display_map.update(cx, |map, _| {
17176            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
17177        });
17178        cx.notify();
17179    }
17180
17181    pub fn text_highlights<'a, T: 'static>(
17182        &'a self,
17183        cx: &'a App,
17184    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
17185        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
17186    }
17187
17188    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
17189        let cleared = self
17190            .display_map
17191            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
17192        if cleared {
17193            cx.notify();
17194        }
17195    }
17196
17197    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
17198        (self.read_only(cx) || self.blink_manager.read(cx).visible())
17199            && self.focus_handle.is_focused(window)
17200    }
17201
17202    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
17203        self.show_cursor_when_unfocused = is_enabled;
17204        cx.notify();
17205    }
17206
17207    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
17208        cx.notify();
17209    }
17210
17211    fn on_buffer_event(
17212        &mut self,
17213        multibuffer: &Entity<MultiBuffer>,
17214        event: &multi_buffer::Event,
17215        window: &mut Window,
17216        cx: &mut Context<Self>,
17217    ) {
17218        match event {
17219            multi_buffer::Event::Edited {
17220                singleton_buffer_edited,
17221                edited_buffer: buffer_edited,
17222            } => {
17223                self.scrollbar_marker_state.dirty = true;
17224                self.active_indent_guides_state.dirty = true;
17225                self.refresh_active_diagnostics(cx);
17226                self.refresh_code_actions(window, cx);
17227                if self.has_active_inline_completion() {
17228                    self.update_visible_inline_completion(window, cx);
17229                }
17230                if let Some(buffer) = buffer_edited {
17231                    let buffer_id = buffer.read(cx).remote_id();
17232                    if !self.registered_buffers.contains_key(&buffer_id) {
17233                        if let Some(project) = self.project.as_ref() {
17234                            project.update(cx, |project, cx| {
17235                                self.registered_buffers.insert(
17236                                    buffer_id,
17237                                    project.register_buffer_with_language_servers(&buffer, cx),
17238                                );
17239                            })
17240                        }
17241                    }
17242                }
17243                cx.emit(EditorEvent::BufferEdited);
17244                cx.emit(SearchEvent::MatchesInvalidated);
17245                if *singleton_buffer_edited {
17246                    if let Some(project) = &self.project {
17247                        #[allow(clippy::mutable_key_type)]
17248                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
17249                            multibuffer
17250                                .all_buffers()
17251                                .into_iter()
17252                                .filter_map(|buffer| {
17253                                    buffer.update(cx, |buffer, cx| {
17254                                        let language = buffer.language()?;
17255                                        let should_discard = project.update(cx, |project, cx| {
17256                                            project.is_local()
17257                                                && !project.has_language_servers_for(buffer, cx)
17258                                        });
17259                                        should_discard.not().then_some(language.clone())
17260                                    })
17261                                })
17262                                .collect::<HashSet<_>>()
17263                        });
17264                        if !languages_affected.is_empty() {
17265                            self.refresh_inlay_hints(
17266                                InlayHintRefreshReason::BufferEdited(languages_affected),
17267                                cx,
17268                            );
17269                        }
17270                    }
17271                }
17272
17273                let Some(project) = &self.project else { return };
17274                let (telemetry, is_via_ssh) = {
17275                    let project = project.read(cx);
17276                    let telemetry = project.client().telemetry().clone();
17277                    let is_via_ssh = project.is_via_ssh();
17278                    (telemetry, is_via_ssh)
17279                };
17280                refresh_linked_ranges(self, window, cx);
17281                telemetry.log_edit_event("editor", is_via_ssh);
17282            }
17283            multi_buffer::Event::ExcerptsAdded {
17284                buffer,
17285                predecessor,
17286                excerpts,
17287            } => {
17288                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17289                let buffer_id = buffer.read(cx).remote_id();
17290                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
17291                    if let Some(project) = &self.project {
17292                        get_uncommitted_diff_for_buffer(
17293                            project,
17294                            [buffer.clone()],
17295                            self.buffer.clone(),
17296                            cx,
17297                        )
17298                        .detach();
17299                    }
17300                }
17301                cx.emit(EditorEvent::ExcerptsAdded {
17302                    buffer: buffer.clone(),
17303                    predecessor: *predecessor,
17304                    excerpts: excerpts.clone(),
17305                });
17306                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17307            }
17308            multi_buffer::Event::ExcerptsRemoved { ids } => {
17309                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
17310                let buffer = self.buffer.read(cx);
17311                self.registered_buffers
17312                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
17313                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17314                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
17315            }
17316            multi_buffer::Event::ExcerptsEdited {
17317                excerpt_ids,
17318                buffer_ids,
17319            } => {
17320                self.display_map.update(cx, |map, cx| {
17321                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
17322                });
17323                cx.emit(EditorEvent::ExcerptsEdited {
17324                    ids: excerpt_ids.clone(),
17325                })
17326            }
17327            multi_buffer::Event::ExcerptsExpanded { ids } => {
17328                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17329                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
17330            }
17331            multi_buffer::Event::Reparsed(buffer_id) => {
17332                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17333                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17334
17335                cx.emit(EditorEvent::Reparsed(*buffer_id));
17336            }
17337            multi_buffer::Event::DiffHunksToggled => {
17338                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17339            }
17340            multi_buffer::Event::LanguageChanged(buffer_id) => {
17341                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
17342                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17343                cx.emit(EditorEvent::Reparsed(*buffer_id));
17344                cx.notify();
17345            }
17346            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
17347            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
17348            multi_buffer::Event::FileHandleChanged
17349            | multi_buffer::Event::Reloaded
17350            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
17351            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
17352            multi_buffer::Event::DiagnosticsUpdated => {
17353                self.refresh_active_diagnostics(cx);
17354                self.refresh_inline_diagnostics(true, window, cx);
17355                self.scrollbar_marker_state.dirty = true;
17356                cx.notify();
17357            }
17358            _ => {}
17359        };
17360    }
17361
17362    fn on_display_map_changed(
17363        &mut self,
17364        _: Entity<DisplayMap>,
17365        _: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) {
17368        cx.notify();
17369    }
17370
17371    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17372        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17373        self.update_edit_prediction_settings(cx);
17374        self.refresh_inline_completion(true, false, window, cx);
17375        self.refresh_inlay_hints(
17376            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
17377                self.selections.newest_anchor().head(),
17378                &self.buffer.read(cx).snapshot(cx),
17379                cx,
17380            )),
17381            cx,
17382        );
17383
17384        let old_cursor_shape = self.cursor_shape;
17385
17386        {
17387            let editor_settings = EditorSettings::get_global(cx);
17388            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
17389            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
17390            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
17391            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
17392        }
17393
17394        if old_cursor_shape != self.cursor_shape {
17395            cx.emit(EditorEvent::CursorShapeChanged);
17396        }
17397
17398        let project_settings = ProjectSettings::get_global(cx);
17399        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
17400
17401        if self.mode.is_full() {
17402            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
17403            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
17404            if self.show_inline_diagnostics != show_inline_diagnostics {
17405                self.show_inline_diagnostics = show_inline_diagnostics;
17406                self.refresh_inline_diagnostics(false, window, cx);
17407            }
17408
17409            if self.git_blame_inline_enabled != inline_blame_enabled {
17410                self.toggle_git_blame_inline_internal(false, window, cx);
17411            }
17412        }
17413
17414        cx.notify();
17415    }
17416
17417    pub fn set_searchable(&mut self, searchable: bool) {
17418        self.searchable = searchable;
17419    }
17420
17421    pub fn searchable(&self) -> bool {
17422        self.searchable
17423    }
17424
17425    fn open_proposed_changes_editor(
17426        &mut self,
17427        _: &OpenProposedChangesEditor,
17428        window: &mut Window,
17429        cx: &mut Context<Self>,
17430    ) {
17431        let Some(workspace) = self.workspace() else {
17432            cx.propagate();
17433            return;
17434        };
17435
17436        let selections = self.selections.all::<usize>(cx);
17437        let multi_buffer = self.buffer.read(cx);
17438        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17439        let mut new_selections_by_buffer = HashMap::default();
17440        for selection in selections {
17441            for (buffer, range, _) in
17442                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
17443            {
17444                let mut range = range.to_point(buffer);
17445                range.start.column = 0;
17446                range.end.column = buffer.line_len(range.end.row);
17447                new_selections_by_buffer
17448                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
17449                    .or_insert(Vec::new())
17450                    .push(range)
17451            }
17452        }
17453
17454        let proposed_changes_buffers = new_selections_by_buffer
17455            .into_iter()
17456            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
17457            .collect::<Vec<_>>();
17458        let proposed_changes_editor = cx.new(|cx| {
17459            ProposedChangesEditor::new(
17460                "Proposed changes",
17461                proposed_changes_buffers,
17462                self.project.clone(),
17463                window,
17464                cx,
17465            )
17466        });
17467
17468        window.defer(cx, move |window, cx| {
17469            workspace.update(cx, |workspace, cx| {
17470                workspace.active_pane().update(cx, |pane, cx| {
17471                    pane.add_item(
17472                        Box::new(proposed_changes_editor),
17473                        true,
17474                        true,
17475                        None,
17476                        window,
17477                        cx,
17478                    );
17479                });
17480            });
17481        });
17482    }
17483
17484    pub fn open_excerpts_in_split(
17485        &mut self,
17486        _: &OpenExcerptsSplit,
17487        window: &mut Window,
17488        cx: &mut Context<Self>,
17489    ) {
17490        self.open_excerpts_common(None, true, window, cx)
17491    }
17492
17493    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
17494        self.open_excerpts_common(None, false, window, cx)
17495    }
17496
17497    fn open_excerpts_common(
17498        &mut self,
17499        jump_data: Option<JumpData>,
17500        split: bool,
17501        window: &mut Window,
17502        cx: &mut Context<Self>,
17503    ) {
17504        let Some(workspace) = self.workspace() else {
17505            cx.propagate();
17506            return;
17507        };
17508
17509        if self.buffer.read(cx).is_singleton() {
17510            cx.propagate();
17511            return;
17512        }
17513
17514        let mut new_selections_by_buffer = HashMap::default();
17515        match &jump_data {
17516            Some(JumpData::MultiBufferPoint {
17517                excerpt_id,
17518                position,
17519                anchor,
17520                line_offset_from_top,
17521            }) => {
17522                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17523                if let Some(buffer) = multi_buffer_snapshot
17524                    .buffer_id_for_excerpt(*excerpt_id)
17525                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
17526                {
17527                    let buffer_snapshot = buffer.read(cx).snapshot();
17528                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
17529                        language::ToPoint::to_point(anchor, &buffer_snapshot)
17530                    } else {
17531                        buffer_snapshot.clip_point(*position, Bias::Left)
17532                    };
17533                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
17534                    new_selections_by_buffer.insert(
17535                        buffer,
17536                        (
17537                            vec![jump_to_offset..jump_to_offset],
17538                            Some(*line_offset_from_top),
17539                        ),
17540                    );
17541                }
17542            }
17543            Some(JumpData::MultiBufferRow {
17544                row,
17545                line_offset_from_top,
17546            }) => {
17547                let point = MultiBufferPoint::new(row.0, 0);
17548                if let Some((buffer, buffer_point, _)) =
17549                    self.buffer.read(cx).point_to_buffer_point(point, cx)
17550                {
17551                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
17552                    new_selections_by_buffer
17553                        .entry(buffer)
17554                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
17555                        .0
17556                        .push(buffer_offset..buffer_offset)
17557                }
17558            }
17559            None => {
17560                let selections = self.selections.all::<usize>(cx);
17561                let multi_buffer = self.buffer.read(cx);
17562                for selection in selections {
17563                    for (snapshot, range, _, anchor) in multi_buffer
17564                        .snapshot(cx)
17565                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
17566                    {
17567                        if let Some(anchor) = anchor {
17568                            // selection is in a deleted hunk
17569                            let Some(buffer_id) = anchor.buffer_id else {
17570                                continue;
17571                            };
17572                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
17573                                continue;
17574                            };
17575                            let offset = text::ToOffset::to_offset(
17576                                &anchor.text_anchor,
17577                                &buffer_handle.read(cx).snapshot(),
17578                            );
17579                            let range = offset..offset;
17580                            new_selections_by_buffer
17581                                .entry(buffer_handle)
17582                                .or_insert((Vec::new(), None))
17583                                .0
17584                                .push(range)
17585                        } else {
17586                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
17587                            else {
17588                                continue;
17589                            };
17590                            new_selections_by_buffer
17591                                .entry(buffer_handle)
17592                                .or_insert((Vec::new(), None))
17593                                .0
17594                                .push(range)
17595                        }
17596                    }
17597                }
17598            }
17599        }
17600
17601        new_selections_by_buffer
17602            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
17603
17604        if new_selections_by_buffer.is_empty() {
17605            return;
17606        }
17607
17608        // We defer the pane interaction because we ourselves are a workspace item
17609        // and activating a new item causes the pane to call a method on us reentrantly,
17610        // which panics if we're on the stack.
17611        window.defer(cx, move |window, cx| {
17612            workspace.update(cx, |workspace, cx| {
17613                let pane = if split {
17614                    workspace.adjacent_pane(window, cx)
17615                } else {
17616                    workspace.active_pane().clone()
17617                };
17618
17619                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
17620                    let editor = buffer
17621                        .read(cx)
17622                        .file()
17623                        .is_none()
17624                        .then(|| {
17625                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
17626                            // so `workspace.open_project_item` will never find them, always opening a new editor.
17627                            // Instead, we try to activate the existing editor in the pane first.
17628                            let (editor, pane_item_index) =
17629                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
17630                                    let editor = item.downcast::<Editor>()?;
17631                                    let singleton_buffer =
17632                                        editor.read(cx).buffer().read(cx).as_singleton()?;
17633                                    if singleton_buffer == buffer {
17634                                        Some((editor, i))
17635                                    } else {
17636                                        None
17637                                    }
17638                                })?;
17639                            pane.update(cx, |pane, cx| {
17640                                pane.activate_item(pane_item_index, true, true, window, cx)
17641                            });
17642                            Some(editor)
17643                        })
17644                        .flatten()
17645                        .unwrap_or_else(|| {
17646                            workspace.open_project_item::<Self>(
17647                                pane.clone(),
17648                                buffer,
17649                                true,
17650                                true,
17651                                window,
17652                                cx,
17653                            )
17654                        });
17655
17656                    editor.update(cx, |editor, cx| {
17657                        let autoscroll = match scroll_offset {
17658                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
17659                            None => Autoscroll::newest(),
17660                        };
17661                        let nav_history = editor.nav_history.take();
17662                        editor.change_selections(Some(autoscroll), window, cx, |s| {
17663                            s.select_ranges(ranges);
17664                        });
17665                        editor.nav_history = nav_history;
17666                    });
17667                }
17668            })
17669        });
17670    }
17671
17672    // For now, don't allow opening excerpts in buffers that aren't backed by
17673    // regular project files.
17674    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
17675        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
17676    }
17677
17678    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
17679        let snapshot = self.buffer.read(cx).read(cx);
17680        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
17681        Some(
17682            ranges
17683                .iter()
17684                .map(move |range| {
17685                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
17686                })
17687                .collect(),
17688        )
17689    }
17690
17691    fn selection_replacement_ranges(
17692        &self,
17693        range: Range<OffsetUtf16>,
17694        cx: &mut App,
17695    ) -> Vec<Range<OffsetUtf16>> {
17696        let selections = self.selections.all::<OffsetUtf16>(cx);
17697        let newest_selection = selections
17698            .iter()
17699            .max_by_key(|selection| selection.id)
17700            .unwrap();
17701        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
17702        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
17703        let snapshot = self.buffer.read(cx).read(cx);
17704        selections
17705            .into_iter()
17706            .map(|mut selection| {
17707                selection.start.0 =
17708                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
17709                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
17710                snapshot.clip_offset_utf16(selection.start, Bias::Left)
17711                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
17712            })
17713            .collect()
17714    }
17715
17716    fn report_editor_event(
17717        &self,
17718        event_type: &'static str,
17719        file_extension: Option<String>,
17720        cx: &App,
17721    ) {
17722        if cfg!(any(test, feature = "test-support")) {
17723            return;
17724        }
17725
17726        let Some(project) = &self.project else { return };
17727
17728        // If None, we are in a file without an extension
17729        let file = self
17730            .buffer
17731            .read(cx)
17732            .as_singleton()
17733            .and_then(|b| b.read(cx).file());
17734        let file_extension = file_extension.or(file
17735            .as_ref()
17736            .and_then(|file| Path::new(file.file_name(cx)).extension())
17737            .and_then(|e| e.to_str())
17738            .map(|a| a.to_string()));
17739
17740        let vim_mode = cx
17741            .global::<SettingsStore>()
17742            .raw_user_settings()
17743            .get("vim_mode")
17744            == Some(&serde_json::Value::Bool(true));
17745
17746        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
17747        let copilot_enabled = edit_predictions_provider
17748            == language::language_settings::EditPredictionProvider::Copilot;
17749        let copilot_enabled_for_language = self
17750            .buffer
17751            .read(cx)
17752            .language_settings(cx)
17753            .show_edit_predictions;
17754
17755        let project = project.read(cx);
17756        telemetry::event!(
17757            event_type,
17758            file_extension,
17759            vim_mode,
17760            copilot_enabled,
17761            copilot_enabled_for_language,
17762            edit_predictions_provider,
17763            is_via_ssh = project.is_via_ssh(),
17764        );
17765    }
17766
17767    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
17768    /// with each line being an array of {text, highlight} objects.
17769    fn copy_highlight_json(
17770        &mut self,
17771        _: &CopyHighlightJson,
17772        window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        #[derive(Serialize)]
17776        struct Chunk<'a> {
17777            text: String,
17778            highlight: Option<&'a str>,
17779        }
17780
17781        let snapshot = self.buffer.read(cx).snapshot(cx);
17782        let range = self
17783            .selected_text_range(false, window, cx)
17784            .and_then(|selection| {
17785                if selection.range.is_empty() {
17786                    None
17787                } else {
17788                    Some(selection.range)
17789                }
17790            })
17791            .unwrap_or_else(|| 0..snapshot.len());
17792
17793        let chunks = snapshot.chunks(range, true);
17794        let mut lines = Vec::new();
17795        let mut line: VecDeque<Chunk> = VecDeque::new();
17796
17797        let Some(style) = self.style.as_ref() else {
17798            return;
17799        };
17800
17801        for chunk in chunks {
17802            let highlight = chunk
17803                .syntax_highlight_id
17804                .and_then(|id| id.name(&style.syntax));
17805            let mut chunk_lines = chunk.text.split('\n').peekable();
17806            while let Some(text) = chunk_lines.next() {
17807                let mut merged_with_last_token = false;
17808                if let Some(last_token) = line.back_mut() {
17809                    if last_token.highlight == highlight {
17810                        last_token.text.push_str(text);
17811                        merged_with_last_token = true;
17812                    }
17813                }
17814
17815                if !merged_with_last_token {
17816                    line.push_back(Chunk {
17817                        text: text.into(),
17818                        highlight,
17819                    });
17820                }
17821
17822                if chunk_lines.peek().is_some() {
17823                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
17824                        line.pop_front();
17825                    }
17826                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
17827                        line.pop_back();
17828                    }
17829
17830                    lines.push(mem::take(&mut line));
17831                }
17832            }
17833        }
17834
17835        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
17836            return;
17837        };
17838        cx.write_to_clipboard(ClipboardItem::new_string(lines));
17839    }
17840
17841    pub fn open_context_menu(
17842        &mut self,
17843        _: &OpenContextMenu,
17844        window: &mut Window,
17845        cx: &mut Context<Self>,
17846    ) {
17847        self.request_autoscroll(Autoscroll::newest(), cx);
17848        let position = self.selections.newest_display(cx).start;
17849        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
17850    }
17851
17852    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
17853        &self.inlay_hint_cache
17854    }
17855
17856    pub fn replay_insert_event(
17857        &mut self,
17858        text: &str,
17859        relative_utf16_range: Option<Range<isize>>,
17860        window: &mut Window,
17861        cx: &mut Context<Self>,
17862    ) {
17863        if !self.input_enabled {
17864            cx.emit(EditorEvent::InputIgnored { text: text.into() });
17865            return;
17866        }
17867        if let Some(relative_utf16_range) = relative_utf16_range {
17868            let selections = self.selections.all::<OffsetUtf16>(cx);
17869            self.change_selections(None, window, cx, |s| {
17870                let new_ranges = selections.into_iter().map(|range| {
17871                    let start = OffsetUtf16(
17872                        range
17873                            .head()
17874                            .0
17875                            .saturating_add_signed(relative_utf16_range.start),
17876                    );
17877                    let end = OffsetUtf16(
17878                        range
17879                            .head()
17880                            .0
17881                            .saturating_add_signed(relative_utf16_range.end),
17882                    );
17883                    start..end
17884                });
17885                s.select_ranges(new_ranges);
17886            });
17887        }
17888
17889        self.handle_input(text, window, cx);
17890    }
17891
17892    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
17893        let Some(provider) = self.semantics_provider.as_ref() else {
17894            return false;
17895        };
17896
17897        let mut supports = false;
17898        self.buffer().update(cx, |this, cx| {
17899            this.for_each_buffer(|buffer| {
17900                supports |= provider.supports_inlay_hints(buffer, cx);
17901            });
17902        });
17903
17904        supports
17905    }
17906
17907    pub fn is_focused(&self, window: &Window) -> bool {
17908        self.focus_handle.is_focused(window)
17909    }
17910
17911    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17912        cx.emit(EditorEvent::Focused);
17913
17914        if let Some(descendant) = self
17915            .last_focused_descendant
17916            .take()
17917            .and_then(|descendant| descendant.upgrade())
17918        {
17919            window.focus(&descendant);
17920        } else {
17921            if let Some(blame) = self.blame.as_ref() {
17922                blame.update(cx, GitBlame::focus)
17923            }
17924
17925            self.blink_manager.update(cx, BlinkManager::enable);
17926            self.show_cursor_names(window, cx);
17927            self.buffer.update(cx, |buffer, cx| {
17928                buffer.finalize_last_transaction(cx);
17929                if self.leader_peer_id.is_none() {
17930                    buffer.set_active_selections(
17931                        &self.selections.disjoint_anchors(),
17932                        self.selections.line_mode,
17933                        self.cursor_shape,
17934                        cx,
17935                    );
17936                }
17937            });
17938        }
17939    }
17940
17941    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
17942        cx.emit(EditorEvent::FocusedIn)
17943    }
17944
17945    fn handle_focus_out(
17946        &mut self,
17947        event: FocusOutEvent,
17948        _window: &mut Window,
17949        cx: &mut Context<Self>,
17950    ) {
17951        if event.blurred != self.focus_handle {
17952            self.last_focused_descendant = Some(event.blurred);
17953        }
17954        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
17955    }
17956
17957    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17958        self.blink_manager.update(cx, BlinkManager::disable);
17959        self.buffer
17960            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
17961
17962        if let Some(blame) = self.blame.as_ref() {
17963            blame.update(cx, GitBlame::blur)
17964        }
17965        if !self.hover_state.focused(window, cx) {
17966            hide_hover(self, cx);
17967        }
17968        if !self
17969            .context_menu
17970            .borrow()
17971            .as_ref()
17972            .is_some_and(|context_menu| context_menu.focused(window, cx))
17973        {
17974            self.hide_context_menu(window, cx);
17975        }
17976        self.discard_inline_completion(false, cx);
17977        cx.emit(EditorEvent::Blurred);
17978        cx.notify();
17979    }
17980
17981    pub fn register_action<A: Action>(
17982        &mut self,
17983        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
17984    ) -> Subscription {
17985        let id = self.next_editor_action_id.post_inc();
17986        let listener = Arc::new(listener);
17987        self.editor_actions.borrow_mut().insert(
17988            id,
17989            Box::new(move |window, _| {
17990                let listener = listener.clone();
17991                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
17992                    let action = action.downcast_ref().unwrap();
17993                    if phase == DispatchPhase::Bubble {
17994                        listener(action, window, cx)
17995                    }
17996                })
17997            }),
17998        );
17999
18000        let editor_actions = self.editor_actions.clone();
18001        Subscription::new(move || {
18002            editor_actions.borrow_mut().remove(&id);
18003        })
18004    }
18005
18006    pub fn file_header_size(&self) -> u32 {
18007        FILE_HEADER_HEIGHT
18008    }
18009
18010    pub fn restore(
18011        &mut self,
18012        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18013        window: &mut Window,
18014        cx: &mut Context<Self>,
18015    ) {
18016        let workspace = self.workspace();
18017        let project = self.project.as_ref();
18018        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18019            let mut tasks = Vec::new();
18020            for (buffer_id, changes) in revert_changes {
18021                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18022                    buffer.update(cx, |buffer, cx| {
18023                        buffer.edit(
18024                            changes
18025                                .into_iter()
18026                                .map(|(range, text)| (range, text.to_string())),
18027                            None,
18028                            cx,
18029                        );
18030                    });
18031
18032                    if let Some(project) =
18033                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
18034                    {
18035                        project.update(cx, |project, cx| {
18036                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
18037                        })
18038                    }
18039                }
18040            }
18041            tasks
18042        });
18043        cx.spawn_in(window, async move |_, cx| {
18044            for (buffer, task) in save_tasks {
18045                let result = task.await;
18046                if result.is_err() {
18047                    let Some(path) = buffer
18048                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
18049                        .ok()
18050                    else {
18051                        continue;
18052                    };
18053                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
18054                        let Some(task) = cx
18055                            .update_window_entity(&workspace, |workspace, window, cx| {
18056                                workspace
18057                                    .open_path_preview(path, None, false, false, false, window, cx)
18058                            })
18059                            .ok()
18060                        else {
18061                            continue;
18062                        };
18063                        task.await.log_err();
18064                    }
18065                }
18066            }
18067        })
18068        .detach();
18069        self.change_selections(None, window, cx, |selections| selections.refresh());
18070    }
18071
18072    pub fn to_pixel_point(
18073        &self,
18074        source: multi_buffer::Anchor,
18075        editor_snapshot: &EditorSnapshot,
18076        window: &mut Window,
18077    ) -> Option<gpui::Point<Pixels>> {
18078        let source_point = source.to_display_point(editor_snapshot);
18079        self.display_to_pixel_point(source_point, editor_snapshot, window)
18080    }
18081
18082    pub fn display_to_pixel_point(
18083        &self,
18084        source: DisplayPoint,
18085        editor_snapshot: &EditorSnapshot,
18086        window: &mut Window,
18087    ) -> Option<gpui::Point<Pixels>> {
18088        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
18089        let text_layout_details = self.text_layout_details(window);
18090        let scroll_top = text_layout_details
18091            .scroll_anchor
18092            .scroll_position(editor_snapshot)
18093            .y;
18094
18095        if source.row().as_f32() < scroll_top.floor() {
18096            return None;
18097        }
18098        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
18099        let source_y = line_height * (source.row().as_f32() - scroll_top);
18100        Some(gpui::Point::new(source_x, source_y))
18101    }
18102
18103    pub fn has_visible_completions_menu(&self) -> bool {
18104        !self.edit_prediction_preview_is_active()
18105            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
18106                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
18107            })
18108    }
18109
18110    pub fn register_addon<T: Addon>(&mut self, instance: T) {
18111        self.addons
18112            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
18113    }
18114
18115    pub fn unregister_addon<T: Addon>(&mut self) {
18116        self.addons.remove(&std::any::TypeId::of::<T>());
18117    }
18118
18119    pub fn addon<T: Addon>(&self) -> Option<&T> {
18120        let type_id = std::any::TypeId::of::<T>();
18121        self.addons
18122            .get(&type_id)
18123            .and_then(|item| item.to_any().downcast_ref::<T>())
18124    }
18125
18126    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
18127        let text_layout_details = self.text_layout_details(window);
18128        let style = &text_layout_details.editor_style;
18129        let font_id = window.text_system().resolve_font(&style.text.font());
18130        let font_size = style.text.font_size.to_pixels(window.rem_size());
18131        let line_height = style.text.line_height_in_pixels(window.rem_size());
18132        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
18133
18134        gpui::Size::new(em_width, line_height)
18135    }
18136
18137    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
18138        self.load_diff_task.clone()
18139    }
18140
18141    fn read_metadata_from_db(
18142        &mut self,
18143        item_id: u64,
18144        workspace_id: WorkspaceId,
18145        window: &mut Window,
18146        cx: &mut Context<Editor>,
18147    ) {
18148        if self.is_singleton(cx)
18149            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
18150        {
18151            let buffer_snapshot = OnceCell::new();
18152
18153            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
18154                if !folds.is_empty() {
18155                    let snapshot =
18156                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18157                    self.fold_ranges(
18158                        folds
18159                            .into_iter()
18160                            .map(|(start, end)| {
18161                                snapshot.clip_offset(start, Bias::Left)
18162                                    ..snapshot.clip_offset(end, Bias::Right)
18163                            })
18164                            .collect(),
18165                        false,
18166                        window,
18167                        cx,
18168                    );
18169                }
18170            }
18171
18172            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
18173                if !selections.is_empty() {
18174                    let snapshot =
18175                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18176                    self.change_selections(None, window, cx, |s| {
18177                        s.select_ranges(selections.into_iter().map(|(start, end)| {
18178                            snapshot.clip_offset(start, Bias::Left)
18179                                ..snapshot.clip_offset(end, Bias::Right)
18180                        }));
18181                    });
18182                }
18183            };
18184        }
18185
18186        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
18187    }
18188}
18189
18190// Consider user intent and default settings
18191fn choose_completion_range(
18192    completion: &Completion,
18193    intent: CompletionIntent,
18194    buffer: &Entity<Buffer>,
18195    cx: &mut Context<Editor>,
18196) -> Range<usize> {
18197    fn should_replace(
18198        completion: &Completion,
18199        insert_range: &Range<text::Anchor>,
18200        intent: CompletionIntent,
18201        completion_mode_setting: LspInsertMode,
18202        buffer: &Buffer,
18203    ) -> bool {
18204        // specific actions take precedence over settings
18205        match intent {
18206            CompletionIntent::CompleteWithInsert => return false,
18207            CompletionIntent::CompleteWithReplace => return true,
18208            CompletionIntent::Complete | CompletionIntent::Compose => {}
18209        }
18210
18211        match completion_mode_setting {
18212            LspInsertMode::Insert => false,
18213            LspInsertMode::Replace => true,
18214            LspInsertMode::ReplaceSubsequence => {
18215                let mut text_to_replace = buffer.chars_for_range(
18216                    buffer.anchor_before(completion.replace_range.start)
18217                        ..buffer.anchor_after(completion.replace_range.end),
18218                );
18219                let mut completion_text = completion.new_text.chars();
18220
18221                // is `text_to_replace` a subsequence of `completion_text`
18222                text_to_replace
18223                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
18224            }
18225            LspInsertMode::ReplaceSuffix => {
18226                let range_after_cursor = insert_range.end..completion.replace_range.end;
18227
18228                let text_after_cursor = buffer
18229                    .text_for_range(
18230                        buffer.anchor_before(range_after_cursor.start)
18231                            ..buffer.anchor_after(range_after_cursor.end),
18232                    )
18233                    .collect::<String>();
18234                completion.new_text.ends_with(&text_after_cursor)
18235            }
18236        }
18237    }
18238
18239    let buffer = buffer.read(cx);
18240
18241    if let CompletionSource::Lsp {
18242        insert_range: Some(insert_range),
18243        ..
18244    } = &completion.source
18245    {
18246        let completion_mode_setting =
18247            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
18248                .completions
18249                .lsp_insert_mode;
18250
18251        if !should_replace(
18252            completion,
18253            &insert_range,
18254            intent,
18255            completion_mode_setting,
18256            buffer,
18257        ) {
18258            return insert_range.to_offset(buffer);
18259        }
18260    }
18261
18262    completion.replace_range.to_offset(buffer)
18263}
18264
18265fn insert_extra_newline_brackets(
18266    buffer: &MultiBufferSnapshot,
18267    range: Range<usize>,
18268    language: &language::LanguageScope,
18269) -> bool {
18270    let leading_whitespace_len = buffer
18271        .reversed_chars_at(range.start)
18272        .take_while(|c| c.is_whitespace() && *c != '\n')
18273        .map(|c| c.len_utf8())
18274        .sum::<usize>();
18275    let trailing_whitespace_len = buffer
18276        .chars_at(range.end)
18277        .take_while(|c| c.is_whitespace() && *c != '\n')
18278        .map(|c| c.len_utf8())
18279        .sum::<usize>();
18280    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
18281
18282    language.brackets().any(|(pair, enabled)| {
18283        let pair_start = pair.start.trim_end();
18284        let pair_end = pair.end.trim_start();
18285
18286        enabled
18287            && pair.newline
18288            && buffer.contains_str_at(range.end, pair_end)
18289            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
18290    })
18291}
18292
18293fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
18294    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
18295        [(buffer, range, _)] => (*buffer, range.clone()),
18296        _ => return false,
18297    };
18298    let pair = {
18299        let mut result: Option<BracketMatch> = None;
18300
18301        for pair in buffer
18302            .all_bracket_ranges(range.clone())
18303            .filter(move |pair| {
18304                pair.open_range.start <= range.start && pair.close_range.end >= range.end
18305            })
18306        {
18307            let len = pair.close_range.end - pair.open_range.start;
18308
18309            if let Some(existing) = &result {
18310                let existing_len = existing.close_range.end - existing.open_range.start;
18311                if len > existing_len {
18312                    continue;
18313                }
18314            }
18315
18316            result = Some(pair);
18317        }
18318
18319        result
18320    };
18321    let Some(pair) = pair else {
18322        return false;
18323    };
18324    pair.newline_only
18325        && buffer
18326            .chars_for_range(pair.open_range.end..range.start)
18327            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
18328            .all(|c| c.is_whitespace() && c != '\n')
18329}
18330
18331fn get_uncommitted_diff_for_buffer(
18332    project: &Entity<Project>,
18333    buffers: impl IntoIterator<Item = Entity<Buffer>>,
18334    buffer: Entity<MultiBuffer>,
18335    cx: &mut App,
18336) -> Task<()> {
18337    let mut tasks = Vec::new();
18338    project.update(cx, |project, cx| {
18339        for buffer in buffers {
18340            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
18341                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
18342            }
18343        }
18344    });
18345    cx.spawn(async move |cx| {
18346        let diffs = future::join_all(tasks).await;
18347        buffer
18348            .update(cx, |buffer, cx| {
18349                for diff in diffs.into_iter().flatten() {
18350                    buffer.add_diff(diff, cx);
18351                }
18352            })
18353            .ok();
18354    })
18355}
18356
18357fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
18358    let tab_size = tab_size.get() as usize;
18359    let mut width = offset;
18360
18361    for ch in text.chars() {
18362        width += if ch == '\t' {
18363            tab_size - (width % tab_size)
18364        } else {
18365            1
18366        };
18367    }
18368
18369    width - offset
18370}
18371
18372#[cfg(test)]
18373mod tests {
18374    use super::*;
18375
18376    #[test]
18377    fn test_string_size_with_expanded_tabs() {
18378        let nz = |val| NonZeroU32::new(val).unwrap();
18379        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
18380        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
18381        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
18382        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
18383        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
18384        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
18385        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
18386        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
18387    }
18388}
18389
18390/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
18391struct WordBreakingTokenizer<'a> {
18392    input: &'a str,
18393}
18394
18395impl<'a> WordBreakingTokenizer<'a> {
18396    fn new(input: &'a str) -> Self {
18397        Self { input }
18398    }
18399}
18400
18401fn is_char_ideographic(ch: char) -> bool {
18402    use unicode_script::Script::*;
18403    use unicode_script::UnicodeScript;
18404    matches!(ch.script(), Han | Tangut | Yi)
18405}
18406
18407fn is_grapheme_ideographic(text: &str) -> bool {
18408    text.chars().any(is_char_ideographic)
18409}
18410
18411fn is_grapheme_whitespace(text: &str) -> bool {
18412    text.chars().any(|x| x.is_whitespace())
18413}
18414
18415fn should_stay_with_preceding_ideograph(text: &str) -> bool {
18416    text.chars().next().map_or(false, |ch| {
18417        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
18418    })
18419}
18420
18421#[derive(PartialEq, Eq, Debug, Clone, Copy)]
18422enum WordBreakToken<'a> {
18423    Word { token: &'a str, grapheme_len: usize },
18424    InlineWhitespace { token: &'a str, grapheme_len: usize },
18425    Newline,
18426}
18427
18428impl<'a> Iterator for WordBreakingTokenizer<'a> {
18429    /// Yields a span, the count of graphemes in the token, and whether it was
18430    /// whitespace. Note that it also breaks at word boundaries.
18431    type Item = WordBreakToken<'a>;
18432
18433    fn next(&mut self) -> Option<Self::Item> {
18434        use unicode_segmentation::UnicodeSegmentation;
18435        if self.input.is_empty() {
18436            return None;
18437        }
18438
18439        let mut iter = self.input.graphemes(true).peekable();
18440        let mut offset = 0;
18441        let mut grapheme_len = 0;
18442        if let Some(first_grapheme) = iter.next() {
18443            let is_newline = first_grapheme == "\n";
18444            let is_whitespace = is_grapheme_whitespace(first_grapheme);
18445            offset += first_grapheme.len();
18446            grapheme_len += 1;
18447            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
18448                if let Some(grapheme) = iter.peek().copied() {
18449                    if should_stay_with_preceding_ideograph(grapheme) {
18450                        offset += grapheme.len();
18451                        grapheme_len += 1;
18452                    }
18453                }
18454            } else {
18455                let mut words = self.input[offset..].split_word_bound_indices().peekable();
18456                let mut next_word_bound = words.peek().copied();
18457                if next_word_bound.map_or(false, |(i, _)| i == 0) {
18458                    next_word_bound = words.next();
18459                }
18460                while let Some(grapheme) = iter.peek().copied() {
18461                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
18462                        break;
18463                    };
18464                    if is_grapheme_whitespace(grapheme) != is_whitespace
18465                        || (grapheme == "\n") != is_newline
18466                    {
18467                        break;
18468                    };
18469                    offset += grapheme.len();
18470                    grapheme_len += 1;
18471                    iter.next();
18472                }
18473            }
18474            let token = &self.input[..offset];
18475            self.input = &self.input[offset..];
18476            if token == "\n" {
18477                Some(WordBreakToken::Newline)
18478            } else if is_whitespace {
18479                Some(WordBreakToken::InlineWhitespace {
18480                    token,
18481                    grapheme_len,
18482                })
18483            } else {
18484                Some(WordBreakToken::Word {
18485                    token,
18486                    grapheme_len,
18487                })
18488            }
18489        } else {
18490            None
18491        }
18492    }
18493}
18494
18495#[test]
18496fn test_word_breaking_tokenizer() {
18497    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
18498        ("", &[]),
18499        ("  ", &[whitespace("  ", 2)]),
18500        ("Ʒ", &[word("Ʒ", 1)]),
18501        ("Ǽ", &[word("Ǽ", 1)]),
18502        ("", &[word("", 1)]),
18503        ("⋑⋑", &[word("⋑⋑", 2)]),
18504        (
18505            "原理,进而",
18506            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
18507        ),
18508        (
18509            "hello world",
18510            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
18511        ),
18512        (
18513            "hello, world",
18514            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
18515        ),
18516        (
18517            "  hello world",
18518            &[
18519                whitespace("  ", 2),
18520                word("hello", 5),
18521                whitespace(" ", 1),
18522                word("world", 5),
18523            ],
18524        ),
18525        (
18526            "这是什么 \n 钢笔",
18527            &[
18528                word("", 1),
18529                word("", 1),
18530                word("", 1),
18531                word("", 1),
18532                whitespace(" ", 1),
18533                newline(),
18534                whitespace(" ", 1),
18535                word("", 1),
18536                word("", 1),
18537            ],
18538        ),
18539        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
18540    ];
18541
18542    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18543        WordBreakToken::Word {
18544            token,
18545            grapheme_len,
18546        }
18547    }
18548
18549    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18550        WordBreakToken::InlineWhitespace {
18551            token,
18552            grapheme_len,
18553        }
18554    }
18555
18556    fn newline() -> WordBreakToken<'static> {
18557        WordBreakToken::Newline
18558    }
18559
18560    for (input, result) in tests {
18561        assert_eq!(
18562            WordBreakingTokenizer::new(input)
18563                .collect::<Vec<_>>()
18564                .as_slice(),
18565            *result,
18566        );
18567    }
18568}
18569
18570fn wrap_with_prefix(
18571    line_prefix: String,
18572    unwrapped_text: String,
18573    wrap_column: usize,
18574    tab_size: NonZeroU32,
18575    preserve_existing_whitespace: bool,
18576) -> String {
18577    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
18578    let mut wrapped_text = String::new();
18579    let mut current_line = line_prefix.clone();
18580
18581    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
18582    let mut current_line_len = line_prefix_len;
18583    let mut in_whitespace = false;
18584    for token in tokenizer {
18585        let have_preceding_whitespace = in_whitespace;
18586        match token {
18587            WordBreakToken::Word {
18588                token,
18589                grapheme_len,
18590            } => {
18591                in_whitespace = false;
18592                if current_line_len + grapheme_len > wrap_column
18593                    && current_line_len != line_prefix_len
18594                {
18595                    wrapped_text.push_str(current_line.trim_end());
18596                    wrapped_text.push('\n');
18597                    current_line.truncate(line_prefix.len());
18598                    current_line_len = line_prefix_len;
18599                }
18600                current_line.push_str(token);
18601                current_line_len += grapheme_len;
18602            }
18603            WordBreakToken::InlineWhitespace {
18604                mut token,
18605                mut grapheme_len,
18606            } => {
18607                in_whitespace = true;
18608                if have_preceding_whitespace && !preserve_existing_whitespace {
18609                    continue;
18610                }
18611                if !preserve_existing_whitespace {
18612                    token = " ";
18613                    grapheme_len = 1;
18614                }
18615                if current_line_len + grapheme_len > wrap_column {
18616                    wrapped_text.push_str(current_line.trim_end());
18617                    wrapped_text.push('\n');
18618                    current_line.truncate(line_prefix.len());
18619                    current_line_len = line_prefix_len;
18620                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
18621                    current_line.push_str(token);
18622                    current_line_len += grapheme_len;
18623                }
18624            }
18625            WordBreakToken::Newline => {
18626                in_whitespace = true;
18627                if preserve_existing_whitespace {
18628                    wrapped_text.push_str(current_line.trim_end());
18629                    wrapped_text.push('\n');
18630                    current_line.truncate(line_prefix.len());
18631                    current_line_len = line_prefix_len;
18632                } else if have_preceding_whitespace {
18633                    continue;
18634                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
18635                {
18636                    wrapped_text.push_str(current_line.trim_end());
18637                    wrapped_text.push('\n');
18638                    current_line.truncate(line_prefix.len());
18639                    current_line_len = line_prefix_len;
18640                } else if current_line_len != line_prefix_len {
18641                    current_line.push(' ');
18642                    current_line_len += 1;
18643                }
18644            }
18645        }
18646    }
18647
18648    if !current_line.is_empty() {
18649        wrapped_text.push_str(&current_line);
18650    }
18651    wrapped_text
18652}
18653
18654#[test]
18655fn test_wrap_with_prefix() {
18656    assert_eq!(
18657        wrap_with_prefix(
18658            "# ".to_string(),
18659            "abcdefg".to_string(),
18660            4,
18661            NonZeroU32::new(4).unwrap(),
18662            false,
18663        ),
18664        "# abcdefg"
18665    );
18666    assert_eq!(
18667        wrap_with_prefix(
18668            "".to_string(),
18669            "\thello world".to_string(),
18670            8,
18671            NonZeroU32::new(4).unwrap(),
18672            false,
18673        ),
18674        "hello\nworld"
18675    );
18676    assert_eq!(
18677        wrap_with_prefix(
18678            "// ".to_string(),
18679            "xx \nyy zz aa bb cc".to_string(),
18680            12,
18681            NonZeroU32::new(4).unwrap(),
18682            false,
18683        ),
18684        "// xx yy zz\n// aa bb cc"
18685    );
18686    assert_eq!(
18687        wrap_with_prefix(
18688            String::new(),
18689            "这是什么 \n 钢笔".to_string(),
18690            3,
18691            NonZeroU32::new(4).unwrap(),
18692            false,
18693        ),
18694        "这是什\n么 钢\n"
18695    );
18696}
18697
18698pub trait CollaborationHub {
18699    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
18700    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
18701    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
18702}
18703
18704impl CollaborationHub for Entity<Project> {
18705    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
18706        self.read(cx).collaborators()
18707    }
18708
18709    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
18710        self.read(cx).user_store().read(cx).participant_indices()
18711    }
18712
18713    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
18714        let this = self.read(cx);
18715        let user_ids = this.collaborators().values().map(|c| c.user_id);
18716        this.user_store().read_with(cx, |user_store, cx| {
18717            user_store.participant_names(user_ids, cx)
18718        })
18719    }
18720}
18721
18722pub trait SemanticsProvider {
18723    fn hover(
18724        &self,
18725        buffer: &Entity<Buffer>,
18726        position: text::Anchor,
18727        cx: &mut App,
18728    ) -> Option<Task<Vec<project::Hover>>>;
18729
18730    fn inlay_hints(
18731        &self,
18732        buffer_handle: Entity<Buffer>,
18733        range: Range<text::Anchor>,
18734        cx: &mut App,
18735    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
18736
18737    fn resolve_inlay_hint(
18738        &self,
18739        hint: InlayHint,
18740        buffer_handle: Entity<Buffer>,
18741        server_id: LanguageServerId,
18742        cx: &mut App,
18743    ) -> Option<Task<anyhow::Result<InlayHint>>>;
18744
18745    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
18746
18747    fn document_highlights(
18748        &self,
18749        buffer: &Entity<Buffer>,
18750        position: text::Anchor,
18751        cx: &mut App,
18752    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
18753
18754    fn definitions(
18755        &self,
18756        buffer: &Entity<Buffer>,
18757        position: text::Anchor,
18758        kind: GotoDefinitionKind,
18759        cx: &mut App,
18760    ) -> Option<Task<Result<Vec<LocationLink>>>>;
18761
18762    fn range_for_rename(
18763        &self,
18764        buffer: &Entity<Buffer>,
18765        position: text::Anchor,
18766        cx: &mut App,
18767    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
18768
18769    fn perform_rename(
18770        &self,
18771        buffer: &Entity<Buffer>,
18772        position: text::Anchor,
18773        new_name: String,
18774        cx: &mut App,
18775    ) -> Option<Task<Result<ProjectTransaction>>>;
18776}
18777
18778pub trait CompletionProvider {
18779    fn completions(
18780        &self,
18781        excerpt_id: ExcerptId,
18782        buffer: &Entity<Buffer>,
18783        buffer_position: text::Anchor,
18784        trigger: CompletionContext,
18785        window: &mut Window,
18786        cx: &mut Context<Editor>,
18787    ) -> Task<Result<Option<Vec<Completion>>>>;
18788
18789    fn resolve_completions(
18790        &self,
18791        buffer: Entity<Buffer>,
18792        completion_indices: Vec<usize>,
18793        completions: Rc<RefCell<Box<[Completion]>>>,
18794        cx: &mut Context<Editor>,
18795    ) -> Task<Result<bool>>;
18796
18797    fn apply_additional_edits_for_completion(
18798        &self,
18799        _buffer: Entity<Buffer>,
18800        _completions: Rc<RefCell<Box<[Completion]>>>,
18801        _completion_index: usize,
18802        _push_to_history: bool,
18803        _cx: &mut Context<Editor>,
18804    ) -> Task<Result<Option<language::Transaction>>> {
18805        Task::ready(Ok(None))
18806    }
18807
18808    fn is_completion_trigger(
18809        &self,
18810        buffer: &Entity<Buffer>,
18811        position: language::Anchor,
18812        text: &str,
18813        trigger_in_words: bool,
18814        cx: &mut Context<Editor>,
18815    ) -> bool;
18816
18817    fn sort_completions(&self) -> bool {
18818        true
18819    }
18820
18821    fn filter_completions(&self) -> bool {
18822        true
18823    }
18824}
18825
18826pub trait CodeActionProvider {
18827    fn id(&self) -> Arc<str>;
18828
18829    fn code_actions(
18830        &self,
18831        buffer: &Entity<Buffer>,
18832        range: Range<text::Anchor>,
18833        window: &mut Window,
18834        cx: &mut App,
18835    ) -> Task<Result<Vec<CodeAction>>>;
18836
18837    fn apply_code_action(
18838        &self,
18839        buffer_handle: Entity<Buffer>,
18840        action: CodeAction,
18841        excerpt_id: ExcerptId,
18842        push_to_history: bool,
18843        window: &mut Window,
18844        cx: &mut App,
18845    ) -> Task<Result<ProjectTransaction>>;
18846}
18847
18848impl CodeActionProvider for Entity<Project> {
18849    fn id(&self) -> Arc<str> {
18850        "project".into()
18851    }
18852
18853    fn code_actions(
18854        &self,
18855        buffer: &Entity<Buffer>,
18856        range: Range<text::Anchor>,
18857        _window: &mut Window,
18858        cx: &mut App,
18859    ) -> Task<Result<Vec<CodeAction>>> {
18860        self.update(cx, |project, cx| {
18861            let code_lens = project.code_lens(buffer, range.clone(), cx);
18862            let code_actions = project.code_actions(buffer, range, None, cx);
18863            cx.background_spawn(async move {
18864                let (code_lens, code_actions) = join(code_lens, code_actions).await;
18865                Ok(code_lens
18866                    .context("code lens fetch")?
18867                    .into_iter()
18868                    .chain(code_actions.context("code action fetch")?)
18869                    .collect())
18870            })
18871        })
18872    }
18873
18874    fn apply_code_action(
18875        &self,
18876        buffer_handle: Entity<Buffer>,
18877        action: CodeAction,
18878        _excerpt_id: ExcerptId,
18879        push_to_history: bool,
18880        _window: &mut Window,
18881        cx: &mut App,
18882    ) -> Task<Result<ProjectTransaction>> {
18883        self.update(cx, |project, cx| {
18884            project.apply_code_action(buffer_handle, action, push_to_history, cx)
18885        })
18886    }
18887}
18888
18889fn snippet_completions(
18890    project: &Project,
18891    buffer: &Entity<Buffer>,
18892    buffer_position: text::Anchor,
18893    cx: &mut App,
18894) -> Task<Result<Vec<Completion>>> {
18895    let languages = buffer.read(cx).languages_at(buffer_position);
18896    let snippet_store = project.snippets().read(cx);
18897
18898    let scopes: Vec<_> = languages
18899        .iter()
18900        .filter_map(|language| {
18901            let language_name = language.lsp_id();
18902            let snippets = snippet_store.snippets_for(Some(language_name), cx);
18903
18904            if snippets.is_empty() {
18905                None
18906            } else {
18907                Some((language.default_scope(), snippets))
18908            }
18909        })
18910        .collect();
18911
18912    if scopes.is_empty() {
18913        return Task::ready(Ok(vec![]));
18914    }
18915
18916    let snapshot = buffer.read(cx).text_snapshot();
18917    let chars: String = snapshot
18918        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
18919        .collect();
18920    let executor = cx.background_executor().clone();
18921
18922    cx.background_spawn(async move {
18923        let mut all_results: Vec<Completion> = Vec::new();
18924        for (scope, snippets) in scopes.into_iter() {
18925            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
18926            let mut last_word = chars
18927                .chars()
18928                .take_while(|c| classifier.is_word(*c))
18929                .collect::<String>();
18930            last_word = last_word.chars().rev().collect();
18931
18932            if last_word.is_empty() {
18933                return Ok(vec![]);
18934            }
18935
18936            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
18937            let to_lsp = |point: &text::Anchor| {
18938                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
18939                point_to_lsp(end)
18940            };
18941            let lsp_end = to_lsp(&buffer_position);
18942
18943            let candidates = snippets
18944                .iter()
18945                .enumerate()
18946                .flat_map(|(ix, snippet)| {
18947                    snippet
18948                        .prefix
18949                        .iter()
18950                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
18951                })
18952                .collect::<Vec<StringMatchCandidate>>();
18953
18954            let mut matches = fuzzy::match_strings(
18955                &candidates,
18956                &last_word,
18957                last_word.chars().any(|c| c.is_uppercase()),
18958                100,
18959                &Default::default(),
18960                executor.clone(),
18961            )
18962            .await;
18963
18964            // Remove all candidates where the query's start does not match the start of any word in the candidate
18965            if let Some(query_start) = last_word.chars().next() {
18966                matches.retain(|string_match| {
18967                    split_words(&string_match.string).any(|word| {
18968                        // Check that the first codepoint of the word as lowercase matches the first
18969                        // codepoint of the query as lowercase
18970                        word.chars()
18971                            .flat_map(|codepoint| codepoint.to_lowercase())
18972                            .zip(query_start.to_lowercase())
18973                            .all(|(word_cp, query_cp)| word_cp == query_cp)
18974                    })
18975                });
18976            }
18977
18978            let matched_strings = matches
18979                .into_iter()
18980                .map(|m| m.string)
18981                .collect::<HashSet<_>>();
18982
18983            let mut result: Vec<Completion> = snippets
18984                .iter()
18985                .filter_map(|snippet| {
18986                    let matching_prefix = snippet
18987                        .prefix
18988                        .iter()
18989                        .find(|prefix| matched_strings.contains(*prefix))?;
18990                    let start = as_offset - last_word.len();
18991                    let start = snapshot.anchor_before(start);
18992                    let range = start..buffer_position;
18993                    let lsp_start = to_lsp(&start);
18994                    let lsp_range = lsp::Range {
18995                        start: lsp_start,
18996                        end: lsp_end,
18997                    };
18998                    Some(Completion {
18999                        replace_range: range,
19000                        new_text: snippet.body.clone(),
19001                        source: CompletionSource::Lsp {
19002                            insert_range: None,
19003                            server_id: LanguageServerId(usize::MAX),
19004                            resolved: true,
19005                            lsp_completion: Box::new(lsp::CompletionItem {
19006                                label: snippet.prefix.first().unwrap().clone(),
19007                                kind: Some(CompletionItemKind::SNIPPET),
19008                                label_details: snippet.description.as_ref().map(|description| {
19009                                    lsp::CompletionItemLabelDetails {
19010                                        detail: Some(description.clone()),
19011                                        description: None,
19012                                    }
19013                                }),
19014                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19015                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19016                                    lsp::InsertReplaceEdit {
19017                                        new_text: snippet.body.clone(),
19018                                        insert: lsp_range,
19019                                        replace: lsp_range,
19020                                    },
19021                                )),
19022                                filter_text: Some(snippet.body.clone()),
19023                                sort_text: Some(char::MAX.to_string()),
19024                                ..lsp::CompletionItem::default()
19025                            }),
19026                            lsp_defaults: None,
19027                        },
19028                        label: CodeLabel {
19029                            text: matching_prefix.clone(),
19030                            runs: Vec::new(),
19031                            filter_range: 0..matching_prefix.len(),
19032                        },
19033                        icon_path: None,
19034                        documentation: snippet.description.clone().map(|description| {
19035                            CompletionDocumentation::SingleLine(description.into())
19036                        }),
19037                        insert_text_mode: None,
19038                        confirm: None,
19039                    })
19040                })
19041                .collect();
19042
19043            all_results.append(&mut result);
19044        }
19045
19046        Ok(all_results)
19047    })
19048}
19049
19050impl CompletionProvider for Entity<Project> {
19051    fn completions(
19052        &self,
19053        _excerpt_id: ExcerptId,
19054        buffer: &Entity<Buffer>,
19055        buffer_position: text::Anchor,
19056        options: CompletionContext,
19057        _window: &mut Window,
19058        cx: &mut Context<Editor>,
19059    ) -> Task<Result<Option<Vec<Completion>>>> {
19060        self.update(cx, |project, cx| {
19061            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19062            let project_completions = project.completions(buffer, buffer_position, options, cx);
19063            cx.background_spawn(async move {
19064                let snippets_completions = snippets.await?;
19065                match project_completions.await? {
19066                    Some(mut completions) => {
19067                        completions.extend(snippets_completions);
19068                        Ok(Some(completions))
19069                    }
19070                    None => {
19071                        if snippets_completions.is_empty() {
19072                            Ok(None)
19073                        } else {
19074                            Ok(Some(snippets_completions))
19075                        }
19076                    }
19077                }
19078            })
19079        })
19080    }
19081
19082    fn resolve_completions(
19083        &self,
19084        buffer: Entity<Buffer>,
19085        completion_indices: Vec<usize>,
19086        completions: Rc<RefCell<Box<[Completion]>>>,
19087        cx: &mut Context<Editor>,
19088    ) -> Task<Result<bool>> {
19089        self.update(cx, |project, cx| {
19090            project.lsp_store().update(cx, |lsp_store, cx| {
19091                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19092            })
19093        })
19094    }
19095
19096    fn apply_additional_edits_for_completion(
19097        &self,
19098        buffer: Entity<Buffer>,
19099        completions: Rc<RefCell<Box<[Completion]>>>,
19100        completion_index: usize,
19101        push_to_history: bool,
19102        cx: &mut Context<Editor>,
19103    ) -> Task<Result<Option<language::Transaction>>> {
19104        self.update(cx, |project, cx| {
19105            project.lsp_store().update(cx, |lsp_store, cx| {
19106                lsp_store.apply_additional_edits_for_completion(
19107                    buffer,
19108                    completions,
19109                    completion_index,
19110                    push_to_history,
19111                    cx,
19112                )
19113            })
19114        })
19115    }
19116
19117    fn is_completion_trigger(
19118        &self,
19119        buffer: &Entity<Buffer>,
19120        position: language::Anchor,
19121        text: &str,
19122        trigger_in_words: bool,
19123        cx: &mut Context<Editor>,
19124    ) -> bool {
19125        let mut chars = text.chars();
19126        let char = if let Some(char) = chars.next() {
19127            char
19128        } else {
19129            return false;
19130        };
19131        if chars.next().is_some() {
19132            return false;
19133        }
19134
19135        let buffer = buffer.read(cx);
19136        let snapshot = buffer.snapshot();
19137        if !snapshot.settings_at(position, cx).show_completions_on_input {
19138            return false;
19139        }
19140        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19141        if trigger_in_words && classifier.is_word(char) {
19142            return true;
19143        }
19144
19145        buffer.completion_triggers().contains(text)
19146    }
19147}
19148
19149impl SemanticsProvider for Entity<Project> {
19150    fn hover(
19151        &self,
19152        buffer: &Entity<Buffer>,
19153        position: text::Anchor,
19154        cx: &mut App,
19155    ) -> Option<Task<Vec<project::Hover>>> {
19156        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19157    }
19158
19159    fn document_highlights(
19160        &self,
19161        buffer: &Entity<Buffer>,
19162        position: text::Anchor,
19163        cx: &mut App,
19164    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19165        Some(self.update(cx, |project, cx| {
19166            project.document_highlights(buffer, position, cx)
19167        }))
19168    }
19169
19170    fn definitions(
19171        &self,
19172        buffer: &Entity<Buffer>,
19173        position: text::Anchor,
19174        kind: GotoDefinitionKind,
19175        cx: &mut App,
19176    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19177        Some(self.update(cx, |project, cx| match kind {
19178            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19179            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19180            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19181            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
19182        }))
19183    }
19184
19185    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
19186        // TODO: make this work for remote projects
19187        self.update(cx, |this, cx| {
19188            buffer.update(cx, |buffer, cx| {
19189                this.any_language_server_supports_inlay_hints(buffer, cx)
19190            })
19191        })
19192    }
19193
19194    fn inlay_hints(
19195        &self,
19196        buffer_handle: Entity<Buffer>,
19197        range: Range<text::Anchor>,
19198        cx: &mut App,
19199    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19200        Some(self.update(cx, |project, cx| {
19201            project.inlay_hints(buffer_handle, range, cx)
19202        }))
19203    }
19204
19205    fn resolve_inlay_hint(
19206        &self,
19207        hint: InlayHint,
19208        buffer_handle: Entity<Buffer>,
19209        server_id: LanguageServerId,
19210        cx: &mut App,
19211    ) -> Option<Task<anyhow::Result<InlayHint>>> {
19212        Some(self.update(cx, |project, cx| {
19213            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
19214        }))
19215    }
19216
19217    fn range_for_rename(
19218        &self,
19219        buffer: &Entity<Buffer>,
19220        position: text::Anchor,
19221        cx: &mut App,
19222    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
19223        Some(self.update(cx, |project, cx| {
19224            let buffer = buffer.clone();
19225            let task = project.prepare_rename(buffer.clone(), position, cx);
19226            cx.spawn(async move |_, cx| {
19227                Ok(match task.await? {
19228                    PrepareRenameResponse::Success(range) => Some(range),
19229                    PrepareRenameResponse::InvalidPosition => None,
19230                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
19231                        // Fallback on using TreeSitter info to determine identifier range
19232                        buffer.update(cx, |buffer, _| {
19233                            let snapshot = buffer.snapshot();
19234                            let (range, kind) = snapshot.surrounding_word(position);
19235                            if kind != Some(CharKind::Word) {
19236                                return None;
19237                            }
19238                            Some(
19239                                snapshot.anchor_before(range.start)
19240                                    ..snapshot.anchor_after(range.end),
19241                            )
19242                        })?
19243                    }
19244                })
19245            })
19246        }))
19247    }
19248
19249    fn perform_rename(
19250        &self,
19251        buffer: &Entity<Buffer>,
19252        position: text::Anchor,
19253        new_name: String,
19254        cx: &mut App,
19255    ) -> Option<Task<Result<ProjectTransaction>>> {
19256        Some(self.update(cx, |project, cx| {
19257            project.perform_rename(buffer.clone(), position, new_name, cx)
19258        }))
19259    }
19260}
19261
19262fn inlay_hint_settings(
19263    location: Anchor,
19264    snapshot: &MultiBufferSnapshot,
19265    cx: &mut Context<Editor>,
19266) -> InlayHintSettings {
19267    let file = snapshot.file_at(location);
19268    let language = snapshot.language_at(location).map(|l| l.name());
19269    language_settings(language, file, cx).inlay_hints
19270}
19271
19272fn consume_contiguous_rows(
19273    contiguous_row_selections: &mut Vec<Selection<Point>>,
19274    selection: &Selection<Point>,
19275    display_map: &DisplaySnapshot,
19276    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
19277) -> (MultiBufferRow, MultiBufferRow) {
19278    contiguous_row_selections.push(selection.clone());
19279    let start_row = MultiBufferRow(selection.start.row);
19280    let mut end_row = ending_row(selection, display_map);
19281
19282    while let Some(next_selection) = selections.peek() {
19283        if next_selection.start.row <= end_row.0 {
19284            end_row = ending_row(next_selection, display_map);
19285            contiguous_row_selections.push(selections.next().unwrap().clone());
19286        } else {
19287            break;
19288        }
19289    }
19290    (start_row, end_row)
19291}
19292
19293fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
19294    if next_selection.end.column > 0 || next_selection.is_empty() {
19295        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
19296    } else {
19297        MultiBufferRow(next_selection.end.row)
19298    }
19299}
19300
19301impl EditorSnapshot {
19302    pub fn remote_selections_in_range<'a>(
19303        &'a self,
19304        range: &'a Range<Anchor>,
19305        collaboration_hub: &dyn CollaborationHub,
19306        cx: &'a App,
19307    ) -> impl 'a + Iterator<Item = RemoteSelection> {
19308        let participant_names = collaboration_hub.user_names(cx);
19309        let participant_indices = collaboration_hub.user_participant_indices(cx);
19310        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
19311        let collaborators_by_replica_id = collaborators_by_peer_id
19312            .iter()
19313            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
19314            .collect::<HashMap<_, _>>();
19315        self.buffer_snapshot
19316            .selections_in_range(range, false)
19317            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
19318                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
19319                let participant_index = participant_indices.get(&collaborator.user_id).copied();
19320                let user_name = participant_names.get(&collaborator.user_id).cloned();
19321                Some(RemoteSelection {
19322                    replica_id,
19323                    selection,
19324                    cursor_shape,
19325                    line_mode,
19326                    participant_index,
19327                    peer_id: collaborator.peer_id,
19328                    user_name,
19329                })
19330            })
19331    }
19332
19333    pub fn hunks_for_ranges(
19334        &self,
19335        ranges: impl IntoIterator<Item = Range<Point>>,
19336    ) -> Vec<MultiBufferDiffHunk> {
19337        let mut hunks = Vec::new();
19338        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
19339            HashMap::default();
19340        for query_range in ranges {
19341            let query_rows =
19342                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
19343            for hunk in self.buffer_snapshot.diff_hunks_in_range(
19344                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
19345            ) {
19346                // Include deleted hunks that are adjacent to the query range, because
19347                // otherwise they would be missed.
19348                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
19349                if hunk.status().is_deleted() {
19350                    intersects_range |= hunk.row_range.start == query_rows.end;
19351                    intersects_range |= hunk.row_range.end == query_rows.start;
19352                }
19353                if intersects_range {
19354                    if !processed_buffer_rows
19355                        .entry(hunk.buffer_id)
19356                        .or_default()
19357                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
19358                    {
19359                        continue;
19360                    }
19361                    hunks.push(hunk);
19362                }
19363            }
19364        }
19365
19366        hunks
19367    }
19368
19369    fn display_diff_hunks_for_rows<'a>(
19370        &'a self,
19371        display_rows: Range<DisplayRow>,
19372        folded_buffers: &'a HashSet<BufferId>,
19373    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
19374        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
19375        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
19376
19377        self.buffer_snapshot
19378            .diff_hunks_in_range(buffer_start..buffer_end)
19379            .filter_map(|hunk| {
19380                if folded_buffers.contains(&hunk.buffer_id) {
19381                    return None;
19382                }
19383
19384                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
19385                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
19386
19387                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
19388                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
19389
19390                let display_hunk = if hunk_display_start.column() != 0 {
19391                    DisplayDiffHunk::Folded {
19392                        display_row: hunk_display_start.row(),
19393                    }
19394                } else {
19395                    let mut end_row = hunk_display_end.row();
19396                    if hunk_display_end.column() > 0 {
19397                        end_row.0 += 1;
19398                    }
19399                    let is_created_file = hunk.is_created_file();
19400                    DisplayDiffHunk::Unfolded {
19401                        status: hunk.status(),
19402                        diff_base_byte_range: hunk.diff_base_byte_range,
19403                        display_row_range: hunk_display_start.row()..end_row,
19404                        multi_buffer_range: Anchor::range_in_buffer(
19405                            hunk.excerpt_id,
19406                            hunk.buffer_id,
19407                            hunk.buffer_range,
19408                        ),
19409                        is_created_file,
19410                    }
19411                };
19412
19413                Some(display_hunk)
19414            })
19415    }
19416
19417    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
19418        self.display_snapshot.buffer_snapshot.language_at(position)
19419    }
19420
19421    pub fn is_focused(&self) -> bool {
19422        self.is_focused
19423    }
19424
19425    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
19426        self.placeholder_text.as_ref()
19427    }
19428
19429    pub fn scroll_position(&self) -> gpui::Point<f32> {
19430        self.scroll_anchor.scroll_position(&self.display_snapshot)
19431    }
19432
19433    fn gutter_dimensions(
19434        &self,
19435        font_id: FontId,
19436        font_size: Pixels,
19437        max_line_number_width: Pixels,
19438        cx: &App,
19439    ) -> Option<GutterDimensions> {
19440        if !self.show_gutter {
19441            return None;
19442        }
19443
19444        let descent = cx.text_system().descent(font_id, font_size);
19445        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
19446        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
19447
19448        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
19449            matches!(
19450                ProjectSettings::get_global(cx).git.git_gutter,
19451                Some(GitGutterSetting::TrackedFiles)
19452            )
19453        });
19454        let gutter_settings = EditorSettings::get_global(cx).gutter;
19455        let show_line_numbers = self
19456            .show_line_numbers
19457            .unwrap_or(gutter_settings.line_numbers);
19458        let line_gutter_width = if show_line_numbers {
19459            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
19460            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
19461            max_line_number_width.max(min_width_for_number_on_gutter)
19462        } else {
19463            0.0.into()
19464        };
19465
19466        let show_code_actions = self
19467            .show_code_actions
19468            .unwrap_or(gutter_settings.code_actions);
19469
19470        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
19471        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
19472
19473        let git_blame_entries_width =
19474            self.git_blame_gutter_max_author_length
19475                .map(|max_author_length| {
19476                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19477                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
19478
19479                    /// The number of characters to dedicate to gaps and margins.
19480                    const SPACING_WIDTH: usize = 4;
19481
19482                    let max_char_count = max_author_length.min(renderer.max_author_length())
19483                        + ::git::SHORT_SHA_LENGTH
19484                        + MAX_RELATIVE_TIMESTAMP.len()
19485                        + SPACING_WIDTH;
19486
19487                    em_advance * max_char_count
19488                });
19489
19490        let is_singleton = self.buffer_snapshot.is_singleton();
19491
19492        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
19493        left_padding += if !is_singleton {
19494            em_width * 4.0
19495        } else if show_code_actions || show_runnables || show_breakpoints {
19496            em_width * 3.0
19497        } else if show_git_gutter && show_line_numbers {
19498            em_width * 2.0
19499        } else if show_git_gutter || show_line_numbers {
19500            em_width
19501        } else {
19502            px(0.)
19503        };
19504
19505        let shows_folds = is_singleton && gutter_settings.folds;
19506
19507        let right_padding = if shows_folds && show_line_numbers {
19508            em_width * 4.0
19509        } else if shows_folds || (!is_singleton && show_line_numbers) {
19510            em_width * 3.0
19511        } else if show_line_numbers {
19512            em_width
19513        } else {
19514            px(0.)
19515        };
19516
19517        Some(GutterDimensions {
19518            left_padding,
19519            right_padding,
19520            width: line_gutter_width + left_padding + right_padding,
19521            margin: -descent,
19522            git_blame_entries_width,
19523        })
19524    }
19525
19526    pub fn render_crease_toggle(
19527        &self,
19528        buffer_row: MultiBufferRow,
19529        row_contains_cursor: bool,
19530        editor: Entity<Editor>,
19531        window: &mut Window,
19532        cx: &mut App,
19533    ) -> Option<AnyElement> {
19534        let folded = self.is_line_folded(buffer_row);
19535        let mut is_foldable = false;
19536
19537        if let Some(crease) = self
19538            .crease_snapshot
19539            .query_row(buffer_row, &self.buffer_snapshot)
19540        {
19541            is_foldable = true;
19542            match crease {
19543                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
19544                    if let Some(render_toggle) = render_toggle {
19545                        let toggle_callback =
19546                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
19547                                if folded {
19548                                    editor.update(cx, |editor, cx| {
19549                                        editor.fold_at(buffer_row, window, cx)
19550                                    });
19551                                } else {
19552                                    editor.update(cx, |editor, cx| {
19553                                        editor.unfold_at(buffer_row, window, cx)
19554                                    });
19555                                }
19556                            });
19557                        return Some((render_toggle)(
19558                            buffer_row,
19559                            folded,
19560                            toggle_callback,
19561                            window,
19562                            cx,
19563                        ));
19564                    }
19565                }
19566            }
19567        }
19568
19569        is_foldable |= self.starts_indent(buffer_row);
19570
19571        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
19572            Some(
19573                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
19574                    .toggle_state(folded)
19575                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
19576                        if folded {
19577                            this.unfold_at(buffer_row, window, cx);
19578                        } else {
19579                            this.fold_at(buffer_row, window, cx);
19580                        }
19581                    }))
19582                    .into_any_element(),
19583            )
19584        } else {
19585            None
19586        }
19587    }
19588
19589    pub fn render_crease_trailer(
19590        &self,
19591        buffer_row: MultiBufferRow,
19592        window: &mut Window,
19593        cx: &mut App,
19594    ) -> Option<AnyElement> {
19595        let folded = self.is_line_folded(buffer_row);
19596        if let Crease::Inline { render_trailer, .. } = self
19597            .crease_snapshot
19598            .query_row(buffer_row, &self.buffer_snapshot)?
19599        {
19600            let render_trailer = render_trailer.as_ref()?;
19601            Some(render_trailer(buffer_row, folded, window, cx))
19602        } else {
19603            None
19604        }
19605    }
19606}
19607
19608impl Deref for EditorSnapshot {
19609    type Target = DisplaySnapshot;
19610
19611    fn deref(&self) -> &Self::Target {
19612        &self.display_snapshot
19613    }
19614}
19615
19616#[derive(Clone, Debug, PartialEq, Eq)]
19617pub enum EditorEvent {
19618    InputIgnored {
19619        text: Arc<str>,
19620    },
19621    InputHandled {
19622        utf16_range_to_replace: Option<Range<isize>>,
19623        text: Arc<str>,
19624    },
19625    ExcerptsAdded {
19626        buffer: Entity<Buffer>,
19627        predecessor: ExcerptId,
19628        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
19629    },
19630    ExcerptsRemoved {
19631        ids: Vec<ExcerptId>,
19632    },
19633    BufferFoldToggled {
19634        ids: Vec<ExcerptId>,
19635        folded: bool,
19636    },
19637    ExcerptsEdited {
19638        ids: Vec<ExcerptId>,
19639    },
19640    ExcerptsExpanded {
19641        ids: Vec<ExcerptId>,
19642    },
19643    BufferEdited,
19644    Edited {
19645        transaction_id: clock::Lamport,
19646    },
19647    Reparsed(BufferId),
19648    Focused,
19649    FocusedIn,
19650    Blurred,
19651    DirtyChanged,
19652    Saved,
19653    TitleChanged,
19654    DiffBaseChanged,
19655    SelectionsChanged {
19656        local: bool,
19657    },
19658    ScrollPositionChanged {
19659        local: bool,
19660        autoscroll: bool,
19661    },
19662    Closed,
19663    TransactionUndone {
19664        transaction_id: clock::Lamport,
19665    },
19666    TransactionBegun {
19667        transaction_id: clock::Lamport,
19668    },
19669    Reloaded,
19670    CursorShapeChanged,
19671    PushedToNavHistory {
19672        anchor: Anchor,
19673        is_deactivate: bool,
19674    },
19675}
19676
19677impl EventEmitter<EditorEvent> for Editor {}
19678
19679impl Focusable for Editor {
19680    fn focus_handle(&self, _cx: &App) -> FocusHandle {
19681        self.focus_handle.clone()
19682    }
19683}
19684
19685impl Render for Editor {
19686    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
19687        let settings = ThemeSettings::get_global(cx);
19688
19689        let mut text_style = match self.mode {
19690            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
19691                color: cx.theme().colors().editor_foreground,
19692                font_family: settings.ui_font.family.clone(),
19693                font_features: settings.ui_font.features.clone(),
19694                font_fallbacks: settings.ui_font.fallbacks.clone(),
19695                font_size: rems(0.875).into(),
19696                font_weight: settings.ui_font.weight,
19697                line_height: relative(settings.buffer_line_height.value()),
19698                ..Default::default()
19699            },
19700            EditorMode::Full { .. } => TextStyle {
19701                color: cx.theme().colors().editor_foreground,
19702                font_family: settings.buffer_font.family.clone(),
19703                font_features: settings.buffer_font.features.clone(),
19704                font_fallbacks: settings.buffer_font.fallbacks.clone(),
19705                font_size: settings.buffer_font_size(cx).into(),
19706                font_weight: settings.buffer_font.weight,
19707                line_height: relative(settings.buffer_line_height.value()),
19708                ..Default::default()
19709            },
19710        };
19711        if let Some(text_style_refinement) = &self.text_style_refinement {
19712            text_style.refine(text_style_refinement)
19713        }
19714
19715        let background = match self.mode {
19716            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
19717            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
19718            EditorMode::Full { .. } => cx.theme().colors().editor_background,
19719        };
19720
19721        EditorElement::new(
19722            &cx.entity(),
19723            EditorStyle {
19724                background,
19725                local_player: cx.theme().players().local(),
19726                text: text_style,
19727                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
19728                syntax: cx.theme().syntax().clone(),
19729                status: cx.theme().status().clone(),
19730                inlay_hints_style: make_inlay_hints_style(cx),
19731                inline_completion_styles: make_suggestion_styles(cx),
19732                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
19733            },
19734        )
19735    }
19736}
19737
19738impl EntityInputHandler for Editor {
19739    fn text_for_range(
19740        &mut self,
19741        range_utf16: Range<usize>,
19742        adjusted_range: &mut Option<Range<usize>>,
19743        _: &mut Window,
19744        cx: &mut Context<Self>,
19745    ) -> Option<String> {
19746        let snapshot = self.buffer.read(cx).read(cx);
19747        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
19748        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
19749        if (start.0..end.0) != range_utf16 {
19750            adjusted_range.replace(start.0..end.0);
19751        }
19752        Some(snapshot.text_for_range(start..end).collect())
19753    }
19754
19755    fn selected_text_range(
19756        &mut self,
19757        ignore_disabled_input: bool,
19758        _: &mut Window,
19759        cx: &mut Context<Self>,
19760    ) -> Option<UTF16Selection> {
19761        // Prevent the IME menu from appearing when holding down an alphabetic key
19762        // while input is disabled.
19763        if !ignore_disabled_input && !self.input_enabled {
19764            return None;
19765        }
19766
19767        let selection = self.selections.newest::<OffsetUtf16>(cx);
19768        let range = selection.range();
19769
19770        Some(UTF16Selection {
19771            range: range.start.0..range.end.0,
19772            reversed: selection.reversed,
19773        })
19774    }
19775
19776    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
19777        let snapshot = self.buffer.read(cx).read(cx);
19778        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
19779        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
19780    }
19781
19782    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19783        self.clear_highlights::<InputComposition>(cx);
19784        self.ime_transaction.take();
19785    }
19786
19787    fn replace_text_in_range(
19788        &mut self,
19789        range_utf16: Option<Range<usize>>,
19790        text: &str,
19791        window: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        if !self.input_enabled {
19795            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19796            return;
19797        }
19798
19799        self.transact(window, cx, |this, window, cx| {
19800            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
19801                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
19802                Some(this.selection_replacement_ranges(range_utf16, cx))
19803            } else {
19804                this.marked_text_ranges(cx)
19805            };
19806
19807            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
19808                let newest_selection_id = this.selections.newest_anchor().id;
19809                this.selections
19810                    .all::<OffsetUtf16>(cx)
19811                    .iter()
19812                    .zip(ranges_to_replace.iter())
19813                    .find_map(|(selection, range)| {
19814                        if selection.id == newest_selection_id {
19815                            Some(
19816                                (range.start.0 as isize - selection.head().0 as isize)
19817                                    ..(range.end.0 as isize - selection.head().0 as isize),
19818                            )
19819                        } else {
19820                            None
19821                        }
19822                    })
19823            });
19824
19825            cx.emit(EditorEvent::InputHandled {
19826                utf16_range_to_replace: range_to_replace,
19827                text: text.into(),
19828            });
19829
19830            if let Some(new_selected_ranges) = new_selected_ranges {
19831                this.change_selections(None, window, cx, |selections| {
19832                    selections.select_ranges(new_selected_ranges)
19833                });
19834                this.backspace(&Default::default(), window, cx);
19835            }
19836
19837            this.handle_input(text, window, cx);
19838        });
19839
19840        if let Some(transaction) = self.ime_transaction {
19841            self.buffer.update(cx, |buffer, cx| {
19842                buffer.group_until_transaction(transaction, cx);
19843            });
19844        }
19845
19846        self.unmark_text(window, cx);
19847    }
19848
19849    fn replace_and_mark_text_in_range(
19850        &mut self,
19851        range_utf16: Option<Range<usize>>,
19852        text: &str,
19853        new_selected_range_utf16: Option<Range<usize>>,
19854        window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        if !self.input_enabled {
19858            return;
19859        }
19860
19861        let transaction = self.transact(window, cx, |this, window, cx| {
19862            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
19863                let snapshot = this.buffer.read(cx).read(cx);
19864                if let Some(relative_range_utf16) = range_utf16.as_ref() {
19865                    for marked_range in &mut marked_ranges {
19866                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
19867                        marked_range.start.0 += relative_range_utf16.start;
19868                        marked_range.start =
19869                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
19870                        marked_range.end =
19871                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
19872                    }
19873                }
19874                Some(marked_ranges)
19875            } else if let Some(range_utf16) = range_utf16 {
19876                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
19877                Some(this.selection_replacement_ranges(range_utf16, cx))
19878            } else {
19879                None
19880            };
19881
19882            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
19883                let newest_selection_id = this.selections.newest_anchor().id;
19884                this.selections
19885                    .all::<OffsetUtf16>(cx)
19886                    .iter()
19887                    .zip(ranges_to_replace.iter())
19888                    .find_map(|(selection, range)| {
19889                        if selection.id == newest_selection_id {
19890                            Some(
19891                                (range.start.0 as isize - selection.head().0 as isize)
19892                                    ..(range.end.0 as isize - selection.head().0 as isize),
19893                            )
19894                        } else {
19895                            None
19896                        }
19897                    })
19898            });
19899
19900            cx.emit(EditorEvent::InputHandled {
19901                utf16_range_to_replace: range_to_replace,
19902                text: text.into(),
19903            });
19904
19905            if let Some(ranges) = ranges_to_replace {
19906                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
19907            }
19908
19909            let marked_ranges = {
19910                let snapshot = this.buffer.read(cx).read(cx);
19911                this.selections
19912                    .disjoint_anchors()
19913                    .iter()
19914                    .map(|selection| {
19915                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
19916                    })
19917                    .collect::<Vec<_>>()
19918            };
19919
19920            if text.is_empty() {
19921                this.unmark_text(window, cx);
19922            } else {
19923                this.highlight_text::<InputComposition>(
19924                    marked_ranges.clone(),
19925                    HighlightStyle {
19926                        underline: Some(UnderlineStyle {
19927                            thickness: px(1.),
19928                            color: None,
19929                            wavy: false,
19930                        }),
19931                        ..Default::default()
19932                    },
19933                    cx,
19934                );
19935            }
19936
19937            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
19938            let use_autoclose = this.use_autoclose;
19939            let use_auto_surround = this.use_auto_surround;
19940            this.set_use_autoclose(false);
19941            this.set_use_auto_surround(false);
19942            this.handle_input(text, window, cx);
19943            this.set_use_autoclose(use_autoclose);
19944            this.set_use_auto_surround(use_auto_surround);
19945
19946            if let Some(new_selected_range) = new_selected_range_utf16 {
19947                let snapshot = this.buffer.read(cx).read(cx);
19948                let new_selected_ranges = marked_ranges
19949                    .into_iter()
19950                    .map(|marked_range| {
19951                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
19952                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
19953                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
19954                        snapshot.clip_offset_utf16(new_start, Bias::Left)
19955                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
19956                    })
19957                    .collect::<Vec<_>>();
19958
19959                drop(snapshot);
19960                this.change_selections(None, window, cx, |selections| {
19961                    selections.select_ranges(new_selected_ranges)
19962                });
19963            }
19964        });
19965
19966        self.ime_transaction = self.ime_transaction.or(transaction);
19967        if let Some(transaction) = self.ime_transaction {
19968            self.buffer.update(cx, |buffer, cx| {
19969                buffer.group_until_transaction(transaction, cx);
19970            });
19971        }
19972
19973        if self.text_highlights::<InputComposition>(cx).is_none() {
19974            self.ime_transaction.take();
19975        }
19976    }
19977
19978    fn bounds_for_range(
19979        &mut self,
19980        range_utf16: Range<usize>,
19981        element_bounds: gpui::Bounds<Pixels>,
19982        window: &mut Window,
19983        cx: &mut Context<Self>,
19984    ) -> Option<gpui::Bounds<Pixels>> {
19985        let text_layout_details = self.text_layout_details(window);
19986        let gpui::Size {
19987            width: em_width,
19988            height: line_height,
19989        } = self.character_size(window);
19990
19991        let snapshot = self.snapshot(window, cx);
19992        let scroll_position = snapshot.scroll_position();
19993        let scroll_left = scroll_position.x * em_width;
19994
19995        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
19996        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
19997            + self.gutter_dimensions.width
19998            + self.gutter_dimensions.margin;
19999        let y = line_height * (start.row().as_f32() - scroll_position.y);
20000
20001        Some(Bounds {
20002            origin: element_bounds.origin + point(x, y),
20003            size: size(em_width, line_height),
20004        })
20005    }
20006
20007    fn character_index_for_point(
20008        &mut self,
20009        point: gpui::Point<Pixels>,
20010        _window: &mut Window,
20011        _cx: &mut Context<Self>,
20012    ) -> Option<usize> {
20013        let position_map = self.last_position_map.as_ref()?;
20014        if !position_map.text_hitbox.contains(&point) {
20015            return None;
20016        }
20017        let display_point = position_map.point_for_position(point).previous_valid;
20018        let anchor = position_map
20019            .snapshot
20020            .display_point_to_anchor(display_point, Bias::Left);
20021        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20022        Some(utf16_offset.0)
20023    }
20024}
20025
20026trait SelectionExt {
20027    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20028    fn spanned_rows(
20029        &self,
20030        include_end_if_at_line_start: bool,
20031        map: &DisplaySnapshot,
20032    ) -> Range<MultiBufferRow>;
20033}
20034
20035impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20036    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20037        let start = self
20038            .start
20039            .to_point(&map.buffer_snapshot)
20040            .to_display_point(map);
20041        let end = self
20042            .end
20043            .to_point(&map.buffer_snapshot)
20044            .to_display_point(map);
20045        if self.reversed {
20046            end..start
20047        } else {
20048            start..end
20049        }
20050    }
20051
20052    fn spanned_rows(
20053        &self,
20054        include_end_if_at_line_start: bool,
20055        map: &DisplaySnapshot,
20056    ) -> Range<MultiBufferRow> {
20057        let start = self.start.to_point(&map.buffer_snapshot);
20058        let mut end = self.end.to_point(&map.buffer_snapshot);
20059        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20060            end.row -= 1;
20061        }
20062
20063        let buffer_start = map.prev_line_boundary(start).0;
20064        let buffer_end = map.next_line_boundary(end).0;
20065        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20066    }
20067}
20068
20069impl<T: InvalidationRegion> InvalidationStack<T> {
20070    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20071    where
20072        S: Clone + ToOffset,
20073    {
20074        while let Some(region) = self.last() {
20075            let all_selections_inside_invalidation_ranges =
20076                if selections.len() == region.ranges().len() {
20077                    selections
20078                        .iter()
20079                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20080                        .all(|(selection, invalidation_range)| {
20081                            let head = selection.head().to_offset(buffer);
20082                            invalidation_range.start <= head && invalidation_range.end >= head
20083                        })
20084                } else {
20085                    false
20086                };
20087
20088            if all_selections_inside_invalidation_ranges {
20089                break;
20090            } else {
20091                self.pop();
20092            }
20093        }
20094    }
20095}
20096
20097impl<T> Default for InvalidationStack<T> {
20098    fn default() -> Self {
20099        Self(Default::default())
20100    }
20101}
20102
20103impl<T> Deref for InvalidationStack<T> {
20104    type Target = Vec<T>;
20105
20106    fn deref(&self) -> &Self::Target {
20107        &self.0
20108    }
20109}
20110
20111impl<T> DerefMut for InvalidationStack<T> {
20112    fn deref_mut(&mut self) -> &mut Self::Target {
20113        &mut self.0
20114    }
20115}
20116
20117impl InvalidationRegion for SnippetState {
20118    fn ranges(&self) -> &[Range<Anchor>] {
20119        &self.ranges[self.active_index]
20120    }
20121}
20122
20123pub fn diagnostic_block_renderer(
20124    diagnostic: Diagnostic,
20125    max_message_rows: Option<u8>,
20126    allow_closing: bool,
20127) -> RenderBlock {
20128    let (text_without_backticks, code_ranges) =
20129        highlight_diagnostic_message(&diagnostic, max_message_rows);
20130
20131    Arc::new(move |cx: &mut BlockContext| {
20132        let group_id: SharedString = cx.block_id.to_string().into();
20133
20134        let mut text_style = cx.window.text_style().clone();
20135        text_style.color = diagnostic_style(diagnostic.severity, cx.theme().status());
20136        let theme_settings = ThemeSettings::get_global(cx);
20137        text_style.font_family = theme_settings.buffer_font.family.clone();
20138        text_style.font_style = theme_settings.buffer_font.style;
20139        text_style.font_features = theme_settings.buffer_font.features.clone();
20140        text_style.font_weight = theme_settings.buffer_font.weight;
20141
20142        let multi_line_diagnostic = diagnostic.message.contains('\n');
20143
20144        let buttons = |diagnostic: &Diagnostic| {
20145            if multi_line_diagnostic {
20146                v_flex()
20147            } else {
20148                h_flex()
20149            }
20150            .when(allow_closing, |div| {
20151                div.children(diagnostic.is_primary.then(|| {
20152                    IconButton::new("close-block", IconName::XCircle)
20153                        .icon_color(Color::Muted)
20154                        .size(ButtonSize::Compact)
20155                        .style(ButtonStyle::Transparent)
20156                        .visible_on_hover(group_id.clone())
20157                        .on_click(move |_click, window, cx| {
20158                            window.dispatch_action(Box::new(Cancel), cx)
20159                        })
20160                        .tooltip(|window, cx| {
20161                            Tooltip::for_action("Close Diagnostics", &Cancel, window, cx)
20162                        })
20163                }))
20164            })
20165            .child(
20166                IconButton::new("copy-block", IconName::Copy)
20167                    .icon_color(Color::Muted)
20168                    .size(ButtonSize::Compact)
20169                    .style(ButtonStyle::Transparent)
20170                    .visible_on_hover(group_id.clone())
20171                    .on_click({
20172                        let message = diagnostic.message.clone();
20173                        move |_click, _, cx| {
20174                            cx.write_to_clipboard(ClipboardItem::new_string(message.clone()))
20175                        }
20176                    })
20177                    .tooltip(Tooltip::text("Copy diagnostic message")),
20178            )
20179        };
20180
20181        let icon_size = buttons(&diagnostic).into_any_element().layout_as_root(
20182            AvailableSpace::min_size(),
20183            cx.window,
20184            cx.app,
20185        );
20186
20187        h_flex()
20188            .id(cx.block_id)
20189            .group(group_id.clone())
20190            .relative()
20191            .size_full()
20192            .block_mouse_down()
20193            .pl(cx.gutter_dimensions.width)
20194            .w(cx.max_width - cx.gutter_dimensions.full_width())
20195            .child(
20196                div()
20197                    .flex()
20198                    .w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
20199                    .flex_shrink(),
20200            )
20201            .child(buttons(&diagnostic))
20202            .child(div().flex().flex_shrink_0().child(
20203                StyledText::new(text_without_backticks.clone()).with_default_highlights(
20204                    &text_style,
20205                    code_ranges.iter().map(|range| {
20206                        (
20207                            range.clone(),
20208                            HighlightStyle {
20209                                font_weight: Some(FontWeight::BOLD),
20210                                ..Default::default()
20211                            },
20212                        )
20213                    }),
20214                ),
20215            ))
20216            .into_any_element()
20217    })
20218}
20219
20220fn inline_completion_edit_text(
20221    current_snapshot: &BufferSnapshot,
20222    edits: &[(Range<Anchor>, String)],
20223    edit_preview: &EditPreview,
20224    include_deletions: bool,
20225    cx: &App,
20226) -> HighlightedText {
20227    let edits = edits
20228        .iter()
20229        .map(|(anchor, text)| {
20230            (
20231                anchor.start.text_anchor..anchor.end.text_anchor,
20232                text.clone(),
20233            )
20234        })
20235        .collect::<Vec<_>>();
20236
20237    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20238}
20239
20240pub fn highlight_diagnostic_message(
20241    diagnostic: &Diagnostic,
20242    mut max_message_rows: Option<u8>,
20243) -> (SharedString, Vec<Range<usize>>) {
20244    let mut text_without_backticks = String::new();
20245    let mut code_ranges = Vec::new();
20246
20247    if let Some(source) = &diagnostic.source {
20248        text_without_backticks.push_str(source);
20249        code_ranges.push(0..source.len());
20250        text_without_backticks.push_str(": ");
20251    }
20252
20253    let mut prev_offset = 0;
20254    let mut in_code_block = false;
20255    let has_row_limit = max_message_rows.is_some();
20256    let mut newline_indices = diagnostic
20257        .message
20258        .match_indices('\n')
20259        .filter(|_| has_row_limit)
20260        .map(|(ix, _)| ix)
20261        .fuse()
20262        .peekable();
20263
20264    for (quote_ix, _) in diagnostic
20265        .message
20266        .match_indices('`')
20267        .chain([(diagnostic.message.len(), "")])
20268    {
20269        let mut first_newline_ix = None;
20270        let mut last_newline_ix = None;
20271        while let Some(newline_ix) = newline_indices.peek() {
20272            if *newline_ix < quote_ix {
20273                if first_newline_ix.is_none() {
20274                    first_newline_ix = Some(*newline_ix);
20275                }
20276                last_newline_ix = Some(*newline_ix);
20277
20278                if let Some(rows_left) = &mut max_message_rows {
20279                    if *rows_left == 0 {
20280                        break;
20281                    } else {
20282                        *rows_left -= 1;
20283                    }
20284                }
20285                let _ = newline_indices.next();
20286            } else {
20287                break;
20288            }
20289        }
20290        let prev_len = text_without_backticks.len();
20291        let new_text = &diagnostic.message[prev_offset..first_newline_ix.unwrap_or(quote_ix)];
20292        text_without_backticks.push_str(new_text);
20293        if in_code_block {
20294            code_ranges.push(prev_len..text_without_backticks.len());
20295        }
20296        prev_offset = last_newline_ix.unwrap_or(quote_ix) + 1;
20297        in_code_block = !in_code_block;
20298        if first_newline_ix.map_or(false, |newline_ix| newline_ix < quote_ix) {
20299            text_without_backticks.push_str("...");
20300            break;
20301        }
20302    }
20303
20304    (text_without_backticks.into(), code_ranges)
20305}
20306
20307fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20308    match severity {
20309        DiagnosticSeverity::ERROR => colors.error,
20310        DiagnosticSeverity::WARNING => colors.warning,
20311        DiagnosticSeverity::INFORMATION => colors.info,
20312        DiagnosticSeverity::HINT => colors.info,
20313        _ => colors.ignored,
20314    }
20315}
20316
20317pub fn styled_runs_for_code_label<'a>(
20318    label: &'a CodeLabel,
20319    syntax_theme: &'a theme::SyntaxTheme,
20320) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
20321    let fade_out = HighlightStyle {
20322        fade_out: Some(0.35),
20323        ..Default::default()
20324    };
20325
20326    let mut prev_end = label.filter_range.end;
20327    label
20328        .runs
20329        .iter()
20330        .enumerate()
20331        .flat_map(move |(ix, (range, highlight_id))| {
20332            let style = if let Some(style) = highlight_id.style(syntax_theme) {
20333                style
20334            } else {
20335                return Default::default();
20336            };
20337            let mut muted_style = style;
20338            muted_style.highlight(fade_out);
20339
20340            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
20341            if range.start >= label.filter_range.end {
20342                if range.start > prev_end {
20343                    runs.push((prev_end..range.start, fade_out));
20344                }
20345                runs.push((range.clone(), muted_style));
20346            } else if range.end <= label.filter_range.end {
20347                runs.push((range.clone(), style));
20348            } else {
20349                runs.push((range.start..label.filter_range.end, style));
20350                runs.push((label.filter_range.end..range.end, muted_style));
20351            }
20352            prev_end = cmp::max(prev_end, range.end);
20353
20354            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
20355                runs.push((prev_end..label.text.len(), fade_out));
20356            }
20357
20358            runs
20359        })
20360}
20361
20362pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
20363    let mut prev_index = 0;
20364    let mut prev_codepoint: Option<char> = None;
20365    text.char_indices()
20366        .chain([(text.len(), '\0')])
20367        .filter_map(move |(index, codepoint)| {
20368            let prev_codepoint = prev_codepoint.replace(codepoint)?;
20369            let is_boundary = index == text.len()
20370                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
20371                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
20372            if is_boundary {
20373                let chunk = &text[prev_index..index];
20374                prev_index = index;
20375                Some(chunk)
20376            } else {
20377                None
20378            }
20379        })
20380}
20381
20382pub trait RangeToAnchorExt: Sized {
20383    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
20384
20385    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
20386        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
20387        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
20388    }
20389}
20390
20391impl<T: ToOffset> RangeToAnchorExt for Range<T> {
20392    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
20393        let start_offset = self.start.to_offset(snapshot);
20394        let end_offset = self.end.to_offset(snapshot);
20395        if start_offset == end_offset {
20396            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
20397        } else {
20398            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
20399        }
20400    }
20401}
20402
20403pub trait RowExt {
20404    fn as_f32(&self) -> f32;
20405
20406    fn next_row(&self) -> Self;
20407
20408    fn previous_row(&self) -> Self;
20409
20410    fn minus(&self, other: Self) -> u32;
20411}
20412
20413impl RowExt for DisplayRow {
20414    fn as_f32(&self) -> f32 {
20415        self.0 as f32
20416    }
20417
20418    fn next_row(&self) -> Self {
20419        Self(self.0 + 1)
20420    }
20421
20422    fn previous_row(&self) -> Self {
20423        Self(self.0.saturating_sub(1))
20424    }
20425
20426    fn minus(&self, other: Self) -> u32 {
20427        self.0 - other.0
20428    }
20429}
20430
20431impl RowExt for MultiBufferRow {
20432    fn as_f32(&self) -> f32 {
20433        self.0 as f32
20434    }
20435
20436    fn next_row(&self) -> Self {
20437        Self(self.0 + 1)
20438    }
20439
20440    fn previous_row(&self) -> Self {
20441        Self(self.0.saturating_sub(1))
20442    }
20443
20444    fn minus(&self, other: Self) -> u32 {
20445        self.0 - other.0
20446    }
20447}
20448
20449trait RowRangeExt {
20450    type Row;
20451
20452    fn len(&self) -> usize;
20453
20454    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
20455}
20456
20457impl RowRangeExt for Range<MultiBufferRow> {
20458    type Row = MultiBufferRow;
20459
20460    fn len(&self) -> usize {
20461        (self.end.0 - self.start.0) as usize
20462    }
20463
20464    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
20465        (self.start.0..self.end.0).map(MultiBufferRow)
20466    }
20467}
20468
20469impl RowRangeExt for Range<DisplayRow> {
20470    type Row = DisplayRow;
20471
20472    fn len(&self) -> usize {
20473        (self.end.0 - self.start.0) as usize
20474    }
20475
20476    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
20477        (self.start.0..self.end.0).map(DisplayRow)
20478    }
20479}
20480
20481/// If select range has more than one line, we
20482/// just point the cursor to range.start.
20483fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
20484    if range.start.row == range.end.row {
20485        range
20486    } else {
20487        range.start..range.start
20488    }
20489}
20490pub struct KillRing(ClipboardItem);
20491impl Global for KillRing {}
20492
20493const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
20494
20495enum BreakpointPromptEditAction {
20496    Log,
20497    Condition,
20498    HitCondition,
20499}
20500
20501struct BreakpointPromptEditor {
20502    pub(crate) prompt: Entity<Editor>,
20503    editor: WeakEntity<Editor>,
20504    breakpoint_anchor: Anchor,
20505    breakpoint: Breakpoint,
20506    edit_action: BreakpointPromptEditAction,
20507    block_ids: HashSet<CustomBlockId>,
20508    gutter_dimensions: Arc<Mutex<GutterDimensions>>,
20509    _subscriptions: Vec<Subscription>,
20510}
20511
20512impl BreakpointPromptEditor {
20513    const MAX_LINES: u8 = 4;
20514
20515    fn new(
20516        editor: WeakEntity<Editor>,
20517        breakpoint_anchor: Anchor,
20518        breakpoint: Breakpoint,
20519        edit_action: BreakpointPromptEditAction,
20520        window: &mut Window,
20521        cx: &mut Context<Self>,
20522    ) -> Self {
20523        let base_text = match edit_action {
20524            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
20525            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
20526            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
20527        }
20528        .map(|msg| msg.to_string())
20529        .unwrap_or_default();
20530
20531        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
20532        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
20533
20534        let prompt = cx.new(|cx| {
20535            let mut prompt = Editor::new(
20536                EditorMode::AutoHeight {
20537                    max_lines: Self::MAX_LINES as usize,
20538                },
20539                buffer,
20540                None,
20541                window,
20542                cx,
20543            );
20544            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
20545            prompt.set_show_cursor_when_unfocused(false, cx);
20546            prompt.set_placeholder_text(
20547                match edit_action {
20548                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
20549                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
20550                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
20551                },
20552                cx,
20553            );
20554
20555            prompt
20556        });
20557
20558        Self {
20559            prompt,
20560            editor,
20561            breakpoint_anchor,
20562            breakpoint,
20563            edit_action,
20564            gutter_dimensions: Arc::new(Mutex::new(GutterDimensions::default())),
20565            block_ids: Default::default(),
20566            _subscriptions: vec![],
20567        }
20568    }
20569
20570    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
20571        self.block_ids.extend(block_ids)
20572    }
20573
20574    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
20575        if let Some(editor) = self.editor.upgrade() {
20576            let message = self
20577                .prompt
20578                .read(cx)
20579                .buffer
20580                .read(cx)
20581                .as_singleton()
20582                .expect("A multi buffer in breakpoint prompt isn't possible")
20583                .read(cx)
20584                .as_rope()
20585                .to_string();
20586
20587            editor.update(cx, |editor, cx| {
20588                editor.edit_breakpoint_at_anchor(
20589                    self.breakpoint_anchor,
20590                    self.breakpoint.clone(),
20591                    match self.edit_action {
20592                        BreakpointPromptEditAction::Log => {
20593                            BreakpointEditAction::EditLogMessage(message.into())
20594                        }
20595                        BreakpointPromptEditAction::Condition => {
20596                            BreakpointEditAction::EditCondition(message.into())
20597                        }
20598                        BreakpointPromptEditAction::HitCondition => {
20599                            BreakpointEditAction::EditHitCondition(message.into())
20600                        }
20601                    },
20602                    cx,
20603                );
20604
20605                editor.remove_blocks(self.block_ids.clone(), None, cx);
20606                cx.focus_self(window);
20607            });
20608        }
20609    }
20610
20611    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
20612        self.editor
20613            .update(cx, |editor, cx| {
20614                editor.remove_blocks(self.block_ids.clone(), None, cx);
20615                window.focus(&editor.focus_handle);
20616            })
20617            .log_err();
20618    }
20619
20620    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
20621        let settings = ThemeSettings::get_global(cx);
20622        let text_style = TextStyle {
20623            color: if self.prompt.read(cx).read_only(cx) {
20624                cx.theme().colors().text_disabled
20625            } else {
20626                cx.theme().colors().text
20627            },
20628            font_family: settings.buffer_font.family.clone(),
20629            font_fallbacks: settings.buffer_font.fallbacks.clone(),
20630            font_size: settings.buffer_font_size(cx).into(),
20631            font_weight: settings.buffer_font.weight,
20632            line_height: relative(settings.buffer_line_height.value()),
20633            ..Default::default()
20634        };
20635        EditorElement::new(
20636            &self.prompt,
20637            EditorStyle {
20638                background: cx.theme().colors().editor_background,
20639                local_player: cx.theme().players().local(),
20640                text: text_style,
20641                ..Default::default()
20642            },
20643        )
20644    }
20645}
20646
20647impl Render for BreakpointPromptEditor {
20648    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20649        let gutter_dimensions = *self.gutter_dimensions.lock();
20650        h_flex()
20651            .key_context("Editor")
20652            .bg(cx.theme().colors().editor_background)
20653            .border_y_1()
20654            .border_color(cx.theme().status().info_border)
20655            .size_full()
20656            .py(window.line_height() / 2.5)
20657            .on_action(cx.listener(Self::confirm))
20658            .on_action(cx.listener(Self::cancel))
20659            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
20660            .child(div().flex_1().child(self.render_prompt_editor(cx)))
20661    }
20662}
20663
20664impl Focusable for BreakpointPromptEditor {
20665    fn focus_handle(&self, cx: &App) -> FocusHandle {
20666        self.prompt.focus_handle(cx)
20667    }
20668}
20669
20670fn all_edits_insertions_or_deletions(
20671    edits: &Vec<(Range<Anchor>, String)>,
20672    snapshot: &MultiBufferSnapshot,
20673) -> bool {
20674    let mut all_insertions = true;
20675    let mut all_deletions = true;
20676
20677    for (range, new_text) in edits.iter() {
20678        let range_is_empty = range.to_offset(&snapshot).is_empty();
20679        let text_is_empty = new_text.is_empty();
20680
20681        if range_is_empty != text_is_empty {
20682            if range_is_empty {
20683                all_deletions = false;
20684            } else {
20685                all_insertions = false;
20686            }
20687        } else {
20688            return false;
20689        }
20690
20691        if !all_insertions && !all_deletions {
20692            return false;
20693        }
20694    }
20695    all_insertions || all_deletions
20696}
20697
20698struct MissingEditPredictionKeybindingTooltip;
20699
20700impl Render for MissingEditPredictionKeybindingTooltip {
20701    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20702        ui::tooltip_container(window, cx, |container, _, cx| {
20703            container
20704                .flex_shrink_0()
20705                .max_w_80()
20706                .min_h(rems_from_px(124.))
20707                .justify_between()
20708                .child(
20709                    v_flex()
20710                        .flex_1()
20711                        .text_ui_sm(cx)
20712                        .child(Label::new("Conflict with Accept Keybinding"))
20713                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
20714                )
20715                .child(
20716                    h_flex()
20717                        .pb_1()
20718                        .gap_1()
20719                        .items_end()
20720                        .w_full()
20721                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
20722                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
20723                        }))
20724                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
20725                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
20726                        })),
20727                )
20728        })
20729    }
20730}
20731
20732#[derive(Debug, Clone, Copy, PartialEq)]
20733pub struct LineHighlight {
20734    pub background: Background,
20735    pub border: Option<gpui::Hsla>,
20736}
20737
20738impl From<Hsla> for LineHighlight {
20739    fn from(hsla: Hsla) -> Self {
20740        Self {
20741            background: hsla.into(),
20742            border: None,
20743        }
20744    }
20745}
20746
20747impl From<Background> for LineHighlight {
20748    fn from(background: Background) -> Self {
20749        Self {
20750            background,
20751            border: None,
20752        }
20753    }
20754}
20755
20756fn render_diff_hunk_controls(
20757    row: u32,
20758    status: &DiffHunkStatus,
20759    hunk_range: Range<Anchor>,
20760    is_created_file: bool,
20761    line_height: Pixels,
20762    editor: &Entity<Editor>,
20763    _window: &mut Window,
20764    cx: &mut App,
20765) -> AnyElement {
20766    h_flex()
20767        .h(line_height)
20768        .mr_1()
20769        .gap_1()
20770        .px_0p5()
20771        .pb_1()
20772        .border_x_1()
20773        .border_b_1()
20774        .border_color(cx.theme().colors().border_variant)
20775        .rounded_b_lg()
20776        .bg(cx.theme().colors().editor_background)
20777        .gap_1()
20778        .occlude()
20779        .shadow_md()
20780        .child(if status.has_secondary_hunk() {
20781            Button::new(("stage", row as u64), "Stage")
20782                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
20783                .tooltip({
20784                    let focus_handle = editor.focus_handle(cx);
20785                    move |window, cx| {
20786                        Tooltip::for_action_in(
20787                            "Stage Hunk",
20788                            &::git::ToggleStaged,
20789                            &focus_handle,
20790                            window,
20791                            cx,
20792                        )
20793                    }
20794                })
20795                .on_click({
20796                    let editor = editor.clone();
20797                    move |_event, _window, cx| {
20798                        editor.update(cx, |editor, cx| {
20799                            editor.stage_or_unstage_diff_hunks(
20800                                true,
20801                                vec![hunk_range.start..hunk_range.start],
20802                                cx,
20803                            );
20804                        });
20805                    }
20806                })
20807        } else {
20808            Button::new(("unstage", row as u64), "Unstage")
20809                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
20810                .tooltip({
20811                    let focus_handle = editor.focus_handle(cx);
20812                    move |window, cx| {
20813                        Tooltip::for_action_in(
20814                            "Unstage Hunk",
20815                            &::git::ToggleStaged,
20816                            &focus_handle,
20817                            window,
20818                            cx,
20819                        )
20820                    }
20821                })
20822                .on_click({
20823                    let editor = editor.clone();
20824                    move |_event, _window, cx| {
20825                        editor.update(cx, |editor, cx| {
20826                            editor.stage_or_unstage_diff_hunks(
20827                                false,
20828                                vec![hunk_range.start..hunk_range.start],
20829                                cx,
20830                            );
20831                        });
20832                    }
20833                })
20834        })
20835        .child(
20836            Button::new(("restore", row as u64), "Restore")
20837                .tooltip({
20838                    let focus_handle = editor.focus_handle(cx);
20839                    move |window, cx| {
20840                        Tooltip::for_action_in(
20841                            "Restore Hunk",
20842                            &::git::Restore,
20843                            &focus_handle,
20844                            window,
20845                            cx,
20846                        )
20847                    }
20848                })
20849                .on_click({
20850                    let editor = editor.clone();
20851                    move |_event, window, cx| {
20852                        editor.update(cx, |editor, cx| {
20853                            let snapshot = editor.snapshot(window, cx);
20854                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
20855                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
20856                        });
20857                    }
20858                })
20859                .disabled(is_created_file),
20860        )
20861        .when(
20862            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
20863            |el| {
20864                el.child(
20865                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
20866                        .shape(IconButtonShape::Square)
20867                        .icon_size(IconSize::Small)
20868                        // .disabled(!has_multiple_hunks)
20869                        .tooltip({
20870                            let focus_handle = editor.focus_handle(cx);
20871                            move |window, cx| {
20872                                Tooltip::for_action_in(
20873                                    "Next Hunk",
20874                                    &GoToHunk,
20875                                    &focus_handle,
20876                                    window,
20877                                    cx,
20878                                )
20879                            }
20880                        })
20881                        .on_click({
20882                            let editor = editor.clone();
20883                            move |_event, window, cx| {
20884                                editor.update(cx, |editor, cx| {
20885                                    let snapshot = editor.snapshot(window, cx);
20886                                    let position =
20887                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
20888                                    editor.go_to_hunk_before_or_after_position(
20889                                        &snapshot,
20890                                        position,
20891                                        Direction::Next,
20892                                        window,
20893                                        cx,
20894                                    );
20895                                    editor.expand_selected_diff_hunks(cx);
20896                                });
20897                            }
20898                        }),
20899                )
20900                .child(
20901                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
20902                        .shape(IconButtonShape::Square)
20903                        .icon_size(IconSize::Small)
20904                        // .disabled(!has_multiple_hunks)
20905                        .tooltip({
20906                            let focus_handle = editor.focus_handle(cx);
20907                            move |window, cx| {
20908                                Tooltip::for_action_in(
20909                                    "Previous Hunk",
20910                                    &GoToPreviousHunk,
20911                                    &focus_handle,
20912                                    window,
20913                                    cx,
20914                                )
20915                            }
20916                        })
20917                        .on_click({
20918                            let editor = editor.clone();
20919                            move |_event, window, cx| {
20920                                editor.update(cx, |editor, cx| {
20921                                    let snapshot = editor.snapshot(window, cx);
20922                                    let point =
20923                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
20924                                    editor.go_to_hunk_before_or_after_position(
20925                                        &snapshot,
20926                                        point,
20927                                        Direction::Prev,
20928                                        window,
20929                                        cx,
20930                                    );
20931                                    editor.expand_selected_diff_hunks(cx);
20932                                });
20933                            }
20934                        }),
20935                )
20936            },
20937        )
20938        .into_any_element()
20939}