editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954}
  955
  956enum SelectionDragState {
  957    /// State when no drag related activity is detected.
  958    None,
  959    /// State when the mouse is down on a selection that is about to be dragged.
  960    ReadyToDrag {
  961        selection: Selection<Anchor>,
  962        click_position: gpui::Point<Pixels>,
  963        mouse_down_time: Instant,
  964    },
  965    /// State when the mouse is dragging the selection in the editor.
  966    Dragging {
  967        selection: Selection<Anchor>,
  968        drop_cursor: Selection<Anchor>,
  969        hide_drop_cursor: bool,
  970    },
  971}
  972
  973enum ColumnarSelectionState {
  974    FromMouse {
  975        selection_tail: Anchor,
  976        display_point: Option<DisplayPoint>,
  977    },
  978    FromSelection {
  979        selection_tail: Anchor,
  980    },
  981}
  982
  983/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  984/// a breakpoint on them.
  985#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  986struct PhantomBreakpointIndicator {
  987    display_row: DisplayRow,
  988    /// There's a small debounce between hovering over the line and showing the indicator.
  989    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  990    is_active: bool,
  991    collides_with_existing_breakpoint: bool,
  992}
  993
  994/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  995///
  996/// See the [module level documentation](self) for more information.
  997pub struct Editor {
  998    focus_handle: FocusHandle,
  999    last_focused_descendant: Option<WeakFocusHandle>,
 1000    /// The text buffer being edited
 1001    buffer: Entity<MultiBuffer>,
 1002    /// Map of how text in the buffer should be displayed.
 1003    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1004    pub display_map: Entity<DisplayMap>,
 1005    pub selections: SelectionsCollection,
 1006    pub scroll_manager: ScrollManager,
 1007    /// When inline assist editors are linked, they all render cursors because
 1008    /// typing enters text into each of them, even the ones that aren't focused.
 1009    pub(crate) show_cursor_when_unfocused: bool,
 1010    columnar_selection_state: Option<ColumnarSelectionState>,
 1011    add_selections_state: Option<AddSelectionsState>,
 1012    select_next_state: Option<SelectNextState>,
 1013    select_prev_state: Option<SelectNextState>,
 1014    selection_history: SelectionHistory,
 1015    defer_selection_effects: bool,
 1016    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1017    autoclose_regions: Vec<AutocloseRegion>,
 1018    snippet_stack: InvalidationStack<SnippetState>,
 1019    select_syntax_node_history: SelectSyntaxNodeHistory,
 1020    ime_transaction: Option<TransactionId>,
 1021    pub diagnostics_max_severity: DiagnosticSeverity,
 1022    active_diagnostics: ActiveDiagnostic,
 1023    show_inline_diagnostics: bool,
 1024    inline_diagnostics_update: Task<()>,
 1025    inline_diagnostics_enabled: bool,
 1026    diagnostics_enabled: bool,
 1027    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1028    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1029    hard_wrap: Option<usize>,
 1030
 1031    // TODO: make this a access method
 1032    pub project: Option<Entity<Project>>,
 1033    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1034    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1035    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1036    blink_manager: Entity<BlinkManager>,
 1037    show_cursor_names: bool,
 1038    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1039    pub show_local_selections: bool,
 1040    mode: EditorMode,
 1041    show_breadcrumbs: bool,
 1042    show_gutter: bool,
 1043    show_scrollbars: ScrollbarAxes,
 1044    minimap_visibility: MinimapVisibility,
 1045    offset_content: bool,
 1046    disable_expand_excerpt_buttons: bool,
 1047    show_line_numbers: Option<bool>,
 1048    use_relative_line_numbers: Option<bool>,
 1049    show_git_diff_gutter: Option<bool>,
 1050    show_code_actions: Option<bool>,
 1051    show_runnables: Option<bool>,
 1052    show_breakpoints: Option<bool>,
 1053    show_wrap_guides: Option<bool>,
 1054    show_indent_guides: Option<bool>,
 1055    placeholder_text: Option<Arc<str>>,
 1056    highlight_order: usize,
 1057    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1058    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1059    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1060    scrollbar_marker_state: ScrollbarMarkerState,
 1061    active_indent_guides_state: ActiveIndentGuidesState,
 1062    nav_history: Option<ItemNavHistory>,
 1063    context_menu: RefCell<Option<CodeContextMenu>>,
 1064    context_menu_options: Option<ContextMenuOptions>,
 1065    mouse_context_menu: Option<MouseContextMenu>,
 1066    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1067    inline_blame_popover: Option<InlineBlamePopover>,
 1068    inline_blame_popover_show_task: Option<Task<()>>,
 1069    signature_help_state: SignatureHelpState,
 1070    auto_signature_help: Option<bool>,
 1071    find_all_references_task_sources: Vec<Anchor>,
 1072    next_completion_id: CompletionId,
 1073    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1074    code_actions_task: Option<Task<Result<()>>>,
 1075    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    document_highlights_task: Option<Task<()>>,
 1078    linked_editing_range_task: Option<Task<Option<()>>>,
 1079    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1080    pending_rename: Option<RenameState>,
 1081    searchable: bool,
 1082    cursor_shape: CursorShape,
 1083    current_line_highlight: Option<CurrentLineHighlight>,
 1084    collapse_matches: bool,
 1085    autoindent_mode: Option<AutoindentMode>,
 1086    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1087    input_enabled: bool,
 1088    use_modal_editing: bool,
 1089    read_only: bool,
 1090    leader_id: Option<CollaboratorId>,
 1091    remote_id: Option<ViewId>,
 1092    pub hover_state: HoverState,
 1093    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1094    gutter_hovered: bool,
 1095    hovered_link_state: Option<HoveredLinkState>,
 1096    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1097    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1098    active_inline_completion: Option<InlineCompletionState>,
 1099    /// Used to prevent flickering as the user types while the menu is open
 1100    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1101    edit_prediction_settings: EditPredictionSettings,
 1102    inline_completions_hidden_for_vim_mode: bool,
 1103    show_inline_completions_override: Option<bool>,
 1104    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1105    edit_prediction_preview: EditPredictionPreview,
 1106    edit_prediction_indent_conflict: bool,
 1107    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1108    inlay_hint_cache: InlayHintCache,
 1109    next_inlay_id: usize,
 1110    _subscriptions: Vec<Subscription>,
 1111    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1112    gutter_dimensions: GutterDimensions,
 1113    style: Option<EditorStyle>,
 1114    text_style_refinement: Option<TextStyleRefinement>,
 1115    next_editor_action_id: EditorActionId,
 1116    editor_actions: Rc<
 1117        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1118    >,
 1119    use_autoclose: bool,
 1120    use_auto_surround: bool,
 1121    auto_replace_emoji_shortcode: bool,
 1122    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1123    show_git_blame_gutter: bool,
 1124    show_git_blame_inline: bool,
 1125    show_git_blame_inline_delay_task: Option<Task<()>>,
 1126    git_blame_inline_enabled: bool,
 1127    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1128    serialize_dirty_buffers: bool,
 1129    show_selection_menu: Option<bool>,
 1130    blame: Option<Entity<GitBlame>>,
 1131    blame_subscription: Option<Subscription>,
 1132    custom_context_menu: Option<
 1133        Box<
 1134            dyn 'static
 1135                + Fn(
 1136                    &mut Self,
 1137                    DisplayPoint,
 1138                    &mut Window,
 1139                    &mut Context<Self>,
 1140                ) -> Option<Entity<ui::ContextMenu>>,
 1141        >,
 1142    >,
 1143    last_bounds: Option<Bounds<Pixels>>,
 1144    last_position_map: Option<Rc<PositionMap>>,
 1145    expect_bounds_change: Option<Bounds<Pixels>>,
 1146    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1147    tasks_update_task: Option<Task<()>>,
 1148    breakpoint_store: Option<Entity<BreakpointStore>>,
 1149    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1150    hovered_diff_hunk_row: Option<DisplayRow>,
 1151    pull_diagnostics_task: Task<()>,
 1152    in_project_search: bool,
 1153    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1154    breadcrumb_header: Option<String>,
 1155    focused_block: Option<FocusedBlock>,
 1156    next_scroll_position: NextScrollCursorCenterTopBottom,
 1157    addons: HashMap<TypeId, Box<dyn Addon>>,
 1158    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1159    load_diff_task: Option<Shared<Task<()>>>,
 1160    /// Whether we are temporarily displaying a diff other than git's
 1161    temporary_diff_override: bool,
 1162    selection_mark_mode: bool,
 1163    toggle_fold_multiple_buffers: Task<()>,
 1164    _scroll_cursor_center_top_bottom_task: Task<()>,
 1165    serialize_selections: Task<()>,
 1166    serialize_folds: Task<()>,
 1167    mouse_cursor_hidden: bool,
 1168    minimap: Option<Entity<Self>>,
 1169    hide_mouse_mode: HideMouseMode,
 1170    pub change_list: ChangeList,
 1171    inline_value_cache: InlineValueCache,
 1172    selection_drag_state: SelectionDragState,
 1173    next_color_inlay_id: usize,
 1174    colors: Option<LspColorData>,
 1175    folding_newlines: Task<()>,
 1176}
 1177
 1178#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1179enum NextScrollCursorCenterTopBottom {
 1180    #[default]
 1181    Center,
 1182    Top,
 1183    Bottom,
 1184}
 1185
 1186impl NextScrollCursorCenterTopBottom {
 1187    fn next(&self) -> Self {
 1188        match self {
 1189            Self::Center => Self::Top,
 1190            Self::Top => Self::Bottom,
 1191            Self::Bottom => Self::Center,
 1192        }
 1193    }
 1194}
 1195
 1196#[derive(Clone)]
 1197pub struct EditorSnapshot {
 1198    pub mode: EditorMode,
 1199    show_gutter: bool,
 1200    show_line_numbers: Option<bool>,
 1201    show_git_diff_gutter: Option<bool>,
 1202    show_code_actions: Option<bool>,
 1203    show_runnables: Option<bool>,
 1204    show_breakpoints: Option<bool>,
 1205    git_blame_gutter_max_author_length: Option<usize>,
 1206    pub display_snapshot: DisplaySnapshot,
 1207    pub placeholder_text: Option<Arc<str>>,
 1208    is_focused: bool,
 1209    scroll_anchor: ScrollAnchor,
 1210    ongoing_scroll: OngoingScroll,
 1211    current_line_highlight: CurrentLineHighlight,
 1212    gutter_hovered: bool,
 1213}
 1214
 1215#[derive(Default, Debug, Clone, Copy)]
 1216pub struct GutterDimensions {
 1217    pub left_padding: Pixels,
 1218    pub right_padding: Pixels,
 1219    pub width: Pixels,
 1220    pub margin: Pixels,
 1221    pub git_blame_entries_width: Option<Pixels>,
 1222}
 1223
 1224impl GutterDimensions {
 1225    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1226        Self {
 1227            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1228            ..Default::default()
 1229        }
 1230    }
 1231
 1232    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1233        -cx.text_system().descent(font_id, font_size)
 1234    }
 1235    /// The full width of the space taken up by the gutter.
 1236    pub fn full_width(&self) -> Pixels {
 1237        self.margin + self.width
 1238    }
 1239
 1240    /// The width of the space reserved for the fold indicators,
 1241    /// use alongside 'justify_end' and `gutter_width` to
 1242    /// right align content with the line numbers
 1243    pub fn fold_area_width(&self) -> Pixels {
 1244        self.margin + self.right_padding
 1245    }
 1246}
 1247
 1248struct CharacterDimensions {
 1249    em_width: Pixels,
 1250    em_advance: Pixels,
 1251    line_height: Pixels,
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct RemoteSelection {
 1256    pub replica_id: ReplicaId,
 1257    pub selection: Selection<Anchor>,
 1258    pub cursor_shape: CursorShape,
 1259    pub collaborator_id: CollaboratorId,
 1260    pub line_mode: bool,
 1261    pub user_name: Option<SharedString>,
 1262    pub color: PlayerColor,
 1263}
 1264
 1265#[derive(Clone, Debug)]
 1266struct SelectionHistoryEntry {
 1267    selections: Arc<[Selection<Anchor>]>,
 1268    select_next_state: Option<SelectNextState>,
 1269    select_prev_state: Option<SelectNextState>,
 1270    add_selections_state: Option<AddSelectionsState>,
 1271}
 1272
 1273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1274enum SelectionHistoryMode {
 1275    Normal,
 1276    Undoing,
 1277    Redoing,
 1278    Skipping,
 1279}
 1280
 1281#[derive(Clone, PartialEq, Eq, Hash)]
 1282struct HoveredCursor {
 1283    replica_id: u16,
 1284    selection_id: usize,
 1285}
 1286
 1287impl Default for SelectionHistoryMode {
 1288    fn default() -> Self {
 1289        Self::Normal
 1290    }
 1291}
 1292
 1293#[derive(Debug)]
 1294/// SelectionEffects controls the side-effects of updating the selection.
 1295///
 1296/// The default behaviour does "what you mostly want":
 1297/// - it pushes to the nav history if the cursor moved by >10 lines
 1298/// - it re-triggers completion requests
 1299/// - it scrolls to fit
 1300///
 1301/// You might want to modify these behaviours. For example when doing a "jump"
 1302/// like go to definition, we always want to add to nav history; but when scrolling
 1303/// in vim mode we never do.
 1304///
 1305/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1306/// move.
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .map_or(true, |e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredInlineCompletionProvider {
 1519    provider: Arc<dyn InlineCompletionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601#[derive(Debug, Clone)]
 1602enum InlayHintRefreshReason {
 1603    ModifiersChanged(bool),
 1604    Toggle(bool),
 1605    SettingsChange(InlayHintSettings),
 1606    NewLinesShown,
 1607    BufferEdited(HashSet<Arc<Language>>),
 1608    RefreshRequested,
 1609    ExcerptsRemoved(Vec<ExcerptId>),
 1610}
 1611
 1612impl InlayHintRefreshReason {
 1613    fn description(&self) -> &'static str {
 1614        match self {
 1615            Self::ModifiersChanged(_) => "modifiers changed",
 1616            Self::Toggle(_) => "toggle",
 1617            Self::SettingsChange(_) => "settings change",
 1618            Self::NewLinesShown => "new lines shown",
 1619            Self::BufferEdited(_) => "buffer edited",
 1620            Self::RefreshRequested => "refresh requested",
 1621            Self::ExcerptsRemoved(_) => "excerpts removed",
 1622        }
 1623    }
 1624}
 1625
 1626pub enum FormatTarget {
 1627    Buffers(HashSet<Entity<Buffer>>),
 1628    Ranges(Vec<Range<MultiBufferPoint>>),
 1629}
 1630
 1631pub(crate) struct FocusedBlock {
 1632    id: BlockId,
 1633    focus_handle: WeakFocusHandle,
 1634}
 1635
 1636#[derive(Clone)]
 1637enum JumpData {
 1638    MultiBufferRow {
 1639        row: MultiBufferRow,
 1640        line_offset_from_top: u32,
 1641    },
 1642    MultiBufferPoint {
 1643        excerpt_id: ExcerptId,
 1644        position: Point,
 1645        anchor: text::Anchor,
 1646        line_offset_from_top: u32,
 1647    },
 1648}
 1649
 1650pub enum MultibufferSelectionMode {
 1651    First,
 1652    All,
 1653}
 1654
 1655#[derive(Clone, Copy, Debug, Default)]
 1656pub struct RewrapOptions {
 1657    pub override_language_settings: bool,
 1658    pub preserve_existing_whitespace: bool,
 1659}
 1660
 1661impl Editor {
 1662    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1663        let buffer = cx.new(|cx| Buffer::local("", cx));
 1664        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1665        Self::new(
 1666            EditorMode::SingleLine { auto_width: false },
 1667            buffer,
 1668            None,
 1669            window,
 1670            cx,
 1671        )
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::SingleLine { auto_width: true },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    pub fn auto_height(
 1693        min_lines: usize,
 1694        max_lines: usize,
 1695        window: &mut Window,
 1696        cx: &mut Context<Self>,
 1697    ) -> Self {
 1698        let buffer = cx.new(|cx| Buffer::local("", cx));
 1699        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1700        Self::new(
 1701            EditorMode::AutoHeight {
 1702                min_lines,
 1703                max_lines: Some(max_lines),
 1704            },
 1705            buffer,
 1706            None,
 1707            window,
 1708            cx,
 1709        )
 1710    }
 1711
 1712    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1713    /// The editor grows as tall as needed to fit its content.
 1714    pub fn auto_height_unbounded(
 1715        min_lines: usize,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        let buffer = cx.new(|cx| Buffer::local("", cx));
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(
 1722            EditorMode::AutoHeight {
 1723                min_lines,
 1724                max_lines: None,
 1725            },
 1726            buffer,
 1727            None,
 1728            window,
 1729            cx,
 1730        )
 1731    }
 1732
 1733    pub fn for_buffer(
 1734        buffer: Entity<Buffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1740        Self::new(EditorMode::full(), buffer, project, window, cx)
 1741    }
 1742
 1743    pub fn for_multibuffer(
 1744        buffer: Entity<MultiBuffer>,
 1745        project: Option<Entity<Project>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        Self::new(EditorMode::full(), buffer, project, window, cx)
 1750    }
 1751
 1752    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1753        let mut clone = Self::new(
 1754            self.mode.clone(),
 1755            self.buffer.clone(),
 1756            self.project.clone(),
 1757            window,
 1758            cx,
 1759        );
 1760        self.display_map.update(cx, |display_map, cx| {
 1761            let snapshot = display_map.snapshot(cx);
 1762            clone.display_map.update(cx, |display_map, cx| {
 1763                display_map.set_state(&snapshot, cx);
 1764            });
 1765        });
 1766        clone.folds_did_change(cx);
 1767        clone.selections.clone_state(&self.selections);
 1768        clone.scroll_manager.clone_state(&self.scroll_manager);
 1769        clone.searchable = self.searchable;
 1770        clone.read_only = self.read_only;
 1771        clone
 1772    }
 1773
 1774    pub fn new(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        Editor::new_internal(mode, buffer, project, None, window, cx)
 1782    }
 1783
 1784    fn new_internal(
 1785        mode: EditorMode,
 1786        buffer: Entity<MultiBuffer>,
 1787        project: Option<Entity<Project>>,
 1788        display_map: Option<Entity<DisplayMap>>,
 1789        window: &mut Window,
 1790        cx: &mut Context<Self>,
 1791    ) -> Self {
 1792        debug_assert!(
 1793            display_map.is_none() || mode.is_minimap(),
 1794            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1795        );
 1796
 1797        let full_mode = mode.is_full();
 1798        let is_minimap = mode.is_minimap();
 1799        let diagnostics_max_severity = if full_mode {
 1800            EditorSettings::get_global(cx)
 1801                .diagnostics_max_severity
 1802                .unwrap_or(DiagnosticSeverity::Hint)
 1803        } else {
 1804            DiagnosticSeverity::Off
 1805        };
 1806        let style = window.text_style();
 1807        let font_size = style.font_size.to_pixels(window.rem_size());
 1808        let editor = cx.entity().downgrade();
 1809        let fold_placeholder = FoldPlaceholder {
 1810            constrain_width: true,
 1811            render: Arc::new(move |fold_id, fold_range, cx| {
 1812                let editor = editor.clone();
 1813                div()
 1814                    .id(fold_id)
 1815                    .bg(cx.theme().colors().ghost_element_background)
 1816                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1817                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1818                    .rounded_xs()
 1819                    .size_full()
 1820                    .cursor_pointer()
 1821                    .child("")
 1822                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1823                    .on_click(move |_, _window, cx| {
 1824                        editor
 1825                            .update(cx, |editor, cx| {
 1826                                editor.unfold_ranges(
 1827                                    &[fold_range.start..fold_range.end],
 1828                                    true,
 1829                                    false,
 1830                                    cx,
 1831                                );
 1832                                cx.stop_propagation();
 1833                            })
 1834                            .ok();
 1835                    })
 1836                    .into_any()
 1837            }),
 1838            merge_adjacent: true,
 1839            ..FoldPlaceholder::default()
 1840        };
 1841        let display_map = display_map.unwrap_or_else(|| {
 1842            cx.new(|cx| {
 1843                DisplayMap::new(
 1844                    buffer.clone(),
 1845                    style.font(),
 1846                    font_size,
 1847                    None,
 1848                    FILE_HEADER_HEIGHT,
 1849                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1850                    fold_placeholder,
 1851                    diagnostics_max_severity,
 1852                    cx,
 1853                )
 1854            })
 1855        });
 1856
 1857        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1858
 1859        let blink_manager = cx.new(|cx| {
 1860            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1861            if is_minimap {
 1862                blink_manager.disable(cx);
 1863            }
 1864            blink_manager
 1865        });
 1866
 1867        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1868            .then(|| language_settings::SoftWrap::None);
 1869
 1870        let mut project_subscriptions = Vec::new();
 1871        if full_mode {
 1872            if let Some(project) = project.as_ref() {
 1873                project_subscriptions.push(cx.subscribe_in(
 1874                    project,
 1875                    window,
 1876                    |editor, _, event, window, cx| match event {
 1877                        project::Event::RefreshCodeLens => {
 1878                            // we always query lens with actions, without storing them, always refreshing them
 1879                        }
 1880                        project::Event::RefreshInlayHints => {
 1881                            editor
 1882                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1883                        }
 1884                        project::Event::LanguageServerAdded(..)
 1885                        | project::Event::LanguageServerRemoved(..) => {
 1886                            if editor.tasks_update_task.is_none() {
 1887                                editor.tasks_update_task =
 1888                                    Some(editor.refresh_runnables(window, cx));
 1889                            }
 1890                            editor.update_lsp_data(true, None, window, cx);
 1891                        }
 1892                        project::Event::SnippetEdit(id, snippet_edits) => {
 1893                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1894                                let focus_handle = editor.focus_handle(cx);
 1895                                if focus_handle.is_focused(window) {
 1896                                    let snapshot = buffer.read(cx).snapshot();
 1897                                    for (range, snippet) in snippet_edits {
 1898                                        let editor_range =
 1899                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1900                                        editor
 1901                                            .insert_snippet(
 1902                                                &[editor_range],
 1903                                                snippet.clone(),
 1904                                                window,
 1905                                                cx,
 1906                                            )
 1907                                            .ok();
 1908                                    }
 1909                                }
 1910                            }
 1911                        }
 1912                        _ => {}
 1913                    },
 1914                ));
 1915                if let Some(task_inventory) = project
 1916                    .read(cx)
 1917                    .task_store()
 1918                    .read(cx)
 1919                    .task_inventory()
 1920                    .cloned()
 1921                {
 1922                    project_subscriptions.push(cx.observe_in(
 1923                        &task_inventory,
 1924                        window,
 1925                        |editor, _, window, cx| {
 1926                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1927                        },
 1928                    ));
 1929                };
 1930
 1931                project_subscriptions.push(cx.subscribe_in(
 1932                    &project.read(cx).breakpoint_store(),
 1933                    window,
 1934                    |editor, _, event, window, cx| match event {
 1935                        BreakpointStoreEvent::ClearDebugLines => {
 1936                            editor.clear_row_highlights::<ActiveDebugLine>();
 1937                            editor.refresh_inline_values(cx);
 1938                        }
 1939                        BreakpointStoreEvent::SetDebugLine => {
 1940                            if editor.go_to_active_debug_line(window, cx) {
 1941                                cx.stop_propagation();
 1942                            }
 1943
 1944                            editor.refresh_inline_values(cx);
 1945                        }
 1946                        _ => {}
 1947                    },
 1948                ));
 1949                let git_store = project.read(cx).git_store().clone();
 1950                let project = project.clone();
 1951                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1952                    match event {
 1953                        GitStoreEvent::RepositoryUpdated(
 1954                            _,
 1955                            RepositoryEvent::Updated {
 1956                                new_instance: true, ..
 1957                            },
 1958                            _,
 1959                        ) => {
 1960                            this.load_diff_task = Some(
 1961                                update_uncommitted_diff_for_buffer(
 1962                                    cx.entity(),
 1963                                    &project,
 1964                                    this.buffer.read(cx).all_buffers(),
 1965                                    this.buffer.clone(),
 1966                                    cx,
 1967                                )
 1968                                .shared(),
 1969                            );
 1970                        }
 1971                        _ => {}
 1972                    }
 1973                }));
 1974            }
 1975        }
 1976
 1977        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1978
 1979        let inlay_hint_settings =
 1980            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1981        let focus_handle = cx.focus_handle();
 1982        if !is_minimap {
 1983            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1984                .detach();
 1985            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1986                .detach();
 1987            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1988                .detach();
 1989            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1990                .detach();
 1991            cx.observe_pending_input(window, Self::observe_pending_input)
 1992                .detach();
 1993        }
 1994
 1995        let show_indent_guides = if matches!(
 1996            mode,
 1997            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1998        ) {
 1999            Some(false)
 2000        } else {
 2001            None
 2002        };
 2003
 2004        let breakpoint_store = match (&mode, project.as_ref()) {
 2005            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2006            _ => None,
 2007        };
 2008
 2009        let mut code_action_providers = Vec::new();
 2010        let mut load_uncommitted_diff = None;
 2011        if let Some(project) = project.clone() {
 2012            load_uncommitted_diff = Some(
 2013                update_uncommitted_diff_for_buffer(
 2014                    cx.entity(),
 2015                    &project,
 2016                    buffer.read(cx).all_buffers(),
 2017                    buffer.clone(),
 2018                    cx,
 2019                )
 2020                .shared(),
 2021            );
 2022            code_action_providers.push(Rc::new(project) as Rc<_>);
 2023        }
 2024
 2025        let mut editor = Self {
 2026            focus_handle,
 2027            show_cursor_when_unfocused: false,
 2028            last_focused_descendant: None,
 2029            buffer: buffer.clone(),
 2030            display_map: display_map.clone(),
 2031            selections,
 2032            scroll_manager: ScrollManager::new(cx),
 2033            columnar_selection_state: None,
 2034            add_selections_state: None,
 2035            select_next_state: None,
 2036            select_prev_state: None,
 2037            selection_history: SelectionHistory::default(),
 2038            defer_selection_effects: false,
 2039            deferred_selection_effects_state: None,
 2040            autoclose_regions: Vec::new(),
 2041            snippet_stack: InvalidationStack::default(),
 2042            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2043            ime_transaction: None,
 2044            active_diagnostics: ActiveDiagnostic::None,
 2045            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2046            inline_diagnostics_update: Task::ready(()),
 2047            inline_diagnostics: Vec::new(),
 2048            soft_wrap_mode_override,
 2049            diagnostics_max_severity,
 2050            hard_wrap: None,
 2051            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2052            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2053            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2054            project,
 2055            blink_manager: blink_manager.clone(),
 2056            show_local_selections: true,
 2057            show_scrollbars: ScrollbarAxes {
 2058                horizontal: full_mode,
 2059                vertical: full_mode,
 2060            },
 2061            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2062            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2063            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2064            show_gutter: full_mode,
 2065            show_line_numbers: (!full_mode).then_some(false),
 2066            use_relative_line_numbers: None,
 2067            disable_expand_excerpt_buttons: !full_mode,
 2068            show_git_diff_gutter: None,
 2069            show_code_actions: None,
 2070            show_runnables: None,
 2071            show_breakpoints: None,
 2072            show_wrap_guides: None,
 2073            show_indent_guides,
 2074            placeholder_text: None,
 2075            highlight_order: 0,
 2076            highlighted_rows: HashMap::default(),
 2077            background_highlights: TreeMap::default(),
 2078            gutter_highlights: TreeMap::default(),
 2079            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2080            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2081            nav_history: None,
 2082            context_menu: RefCell::new(None),
 2083            context_menu_options: None,
 2084            mouse_context_menu: None,
 2085            completion_tasks: Vec::new(),
 2086            inline_blame_popover: None,
 2087            inline_blame_popover_show_task: None,
 2088            signature_help_state: SignatureHelpState::default(),
 2089            auto_signature_help: None,
 2090            find_all_references_task_sources: Vec::new(),
 2091            next_completion_id: 0,
 2092            next_inlay_id: 0,
 2093            code_action_providers,
 2094            available_code_actions: None,
 2095            code_actions_task: None,
 2096            quick_selection_highlight_task: None,
 2097            debounced_selection_highlight_task: None,
 2098            document_highlights_task: None,
 2099            linked_editing_range_task: None,
 2100            pending_rename: None,
 2101            searchable: !is_minimap,
 2102            cursor_shape: EditorSettings::get_global(cx)
 2103                .cursor_shape
 2104                .unwrap_or_default(),
 2105            current_line_highlight: None,
 2106            autoindent_mode: Some(AutoindentMode::EachLine),
 2107            collapse_matches: false,
 2108            workspace: None,
 2109            input_enabled: !is_minimap,
 2110            use_modal_editing: full_mode,
 2111            read_only: is_minimap,
 2112            use_autoclose: true,
 2113            use_auto_surround: true,
 2114            auto_replace_emoji_shortcode: false,
 2115            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2116            leader_id: None,
 2117            remote_id: None,
 2118            hover_state: HoverState::default(),
 2119            pending_mouse_down: None,
 2120            hovered_link_state: None,
 2121            edit_prediction_provider: None,
 2122            active_inline_completion: None,
 2123            stale_inline_completion_in_menu: None,
 2124            edit_prediction_preview: EditPredictionPreview::Inactive {
 2125                released_too_fast: false,
 2126            },
 2127            inline_diagnostics_enabled: full_mode,
 2128            diagnostics_enabled: full_mode,
 2129            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2130            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2131            gutter_hovered: false,
 2132            pixel_position_of_newest_cursor: None,
 2133            last_bounds: None,
 2134            last_position_map: None,
 2135            expect_bounds_change: None,
 2136            gutter_dimensions: GutterDimensions::default(),
 2137            style: None,
 2138            show_cursor_names: false,
 2139            hovered_cursors: HashMap::default(),
 2140            next_editor_action_id: EditorActionId::default(),
 2141            editor_actions: Rc::default(),
 2142            inline_completions_hidden_for_vim_mode: false,
 2143            show_inline_completions_override: None,
 2144            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2145            edit_prediction_settings: EditPredictionSettings::Disabled,
 2146            edit_prediction_indent_conflict: false,
 2147            edit_prediction_requires_modifier_in_indent_conflict: true,
 2148            custom_context_menu: None,
 2149            show_git_blame_gutter: false,
 2150            show_git_blame_inline: false,
 2151            show_selection_menu: None,
 2152            show_git_blame_inline_delay_task: None,
 2153            git_blame_inline_enabled: full_mode
 2154                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2155            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2156            serialize_dirty_buffers: !is_minimap
 2157                && ProjectSettings::get_global(cx)
 2158                    .session
 2159                    .restore_unsaved_buffers,
 2160            blame: None,
 2161            blame_subscription: None,
 2162            tasks: BTreeMap::default(),
 2163
 2164            breakpoint_store,
 2165            gutter_breakpoint_indicator: (None, None),
 2166            hovered_diff_hunk_row: None,
 2167            _subscriptions: (!is_minimap)
 2168                .then(|| {
 2169                    vec![
 2170                        cx.observe(&buffer, Self::on_buffer_changed),
 2171                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2172                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2173                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2174                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2175                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2176                        cx.observe_window_activation(window, |editor, window, cx| {
 2177                            let active = window.is_window_active();
 2178                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2179                                if active {
 2180                                    blink_manager.enable(cx);
 2181                                } else {
 2182                                    blink_manager.disable(cx);
 2183                                }
 2184                            });
 2185                            if active {
 2186                                editor.show_mouse_cursor(cx);
 2187                            }
 2188                        }),
 2189                    ]
 2190                })
 2191                .unwrap_or_default(),
 2192            tasks_update_task: None,
 2193            pull_diagnostics_task: Task::ready(()),
 2194            colors: None,
 2195            next_color_inlay_id: 0,
 2196            linked_edit_ranges: Default::default(),
 2197            in_project_search: false,
 2198            previous_search_ranges: None,
 2199            breadcrumb_header: None,
 2200            focused_block: None,
 2201            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2202            addons: HashMap::default(),
 2203            registered_buffers: HashMap::default(),
 2204            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2205            selection_mark_mode: false,
 2206            toggle_fold_multiple_buffers: Task::ready(()),
 2207            serialize_selections: Task::ready(()),
 2208            serialize_folds: Task::ready(()),
 2209            text_style_refinement: None,
 2210            load_diff_task: load_uncommitted_diff,
 2211            temporary_diff_override: false,
 2212            mouse_cursor_hidden: false,
 2213            minimap: None,
 2214            hide_mouse_mode: EditorSettings::get_global(cx)
 2215                .hide_mouse
 2216                .unwrap_or_default(),
 2217            change_list: ChangeList::new(),
 2218            mode,
 2219            selection_drag_state: SelectionDragState::None,
 2220            folding_newlines: Task::ready(()),
 2221        };
 2222
 2223        if is_minimap {
 2224            return editor;
 2225        }
 2226
 2227        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2228            editor
 2229                ._subscriptions
 2230                .push(cx.observe(breakpoints, |_, _, cx| {
 2231                    cx.notify();
 2232                }));
 2233        }
 2234        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2235        editor._subscriptions.extend(project_subscriptions);
 2236
 2237        editor._subscriptions.push(cx.subscribe_in(
 2238            &cx.entity(),
 2239            window,
 2240            |editor, _, e: &EditorEvent, window, cx| match e {
 2241                EditorEvent::ScrollPositionChanged { local, .. } => {
 2242                    if *local {
 2243                        let new_anchor = editor.scroll_manager.anchor();
 2244                        let snapshot = editor.snapshot(window, cx);
 2245                        editor.update_restoration_data(cx, move |data| {
 2246                            data.scroll_position = (
 2247                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2248                                new_anchor.offset,
 2249                            );
 2250                        });
 2251                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2252                        editor.inline_blame_popover.take();
 2253                    }
 2254                }
 2255                EditorEvent::Edited { .. } => {
 2256                    if !vim_enabled(cx) {
 2257                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2258                        let pop_state = editor
 2259                            .change_list
 2260                            .last()
 2261                            .map(|previous| {
 2262                                previous.len() == selections.len()
 2263                                    && previous.iter().enumerate().all(|(ix, p)| {
 2264                                        p.to_display_point(&map).row()
 2265                                            == selections[ix].head().row()
 2266                                    })
 2267                            })
 2268                            .unwrap_or(false);
 2269                        let new_positions = selections
 2270                            .into_iter()
 2271                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2272                            .collect();
 2273                        editor
 2274                            .change_list
 2275                            .push_to_change_list(pop_state, new_positions);
 2276                    }
 2277                }
 2278                _ => (),
 2279            },
 2280        ));
 2281
 2282        if let Some(dap_store) = editor
 2283            .project
 2284            .as_ref()
 2285            .map(|project| project.read(cx).dap_store())
 2286        {
 2287            let weak_editor = cx.weak_entity();
 2288
 2289            editor
 2290                ._subscriptions
 2291                .push(
 2292                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2293                        let session_entity = cx.entity();
 2294                        weak_editor
 2295                            .update(cx, |editor, cx| {
 2296                                editor._subscriptions.push(
 2297                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2298                                );
 2299                            })
 2300                            .ok();
 2301                    }),
 2302                );
 2303
 2304            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2305                editor
 2306                    ._subscriptions
 2307                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2308            }
 2309        }
 2310
 2311        // skip adding the initial selection to selection history
 2312        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2313        editor.end_selection(window, cx);
 2314        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2315
 2316        editor.scroll_manager.show_scrollbars(window, cx);
 2317        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2318
 2319        if full_mode {
 2320            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2321            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2322
 2323            if editor.git_blame_inline_enabled {
 2324                editor.start_git_blame_inline(false, window, cx);
 2325            }
 2326
 2327            editor.go_to_active_debug_line(window, cx);
 2328
 2329            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2330                if let Some(project) = editor.project.as_ref() {
 2331                    let handle = project.update(cx, |project, cx| {
 2332                        project.register_buffer_with_language_servers(&buffer, cx)
 2333                    });
 2334                    editor
 2335                        .registered_buffers
 2336                        .insert(buffer.read(cx).remote_id(), handle);
 2337                }
 2338            }
 2339
 2340            editor.minimap =
 2341                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2342            editor.colors = Some(LspColorData::new(cx));
 2343            editor.update_lsp_data(false, None, window, cx);
 2344        }
 2345
 2346        if editor.mode.is_full() {
 2347            editor.report_editor_event("Editor Opened", None, cx);
 2348        }
 2349
 2350        editor
 2351    }
 2352
 2353    pub fn deploy_mouse_context_menu(
 2354        &mut self,
 2355        position: gpui::Point<Pixels>,
 2356        context_menu: Entity<ContextMenu>,
 2357        window: &mut Window,
 2358        cx: &mut Context<Self>,
 2359    ) {
 2360        self.mouse_context_menu = Some(MouseContextMenu::new(
 2361            self,
 2362            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2363            context_menu,
 2364            window,
 2365            cx,
 2366        ));
 2367    }
 2368
 2369    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2370        self.mouse_context_menu
 2371            .as_ref()
 2372            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2373    }
 2374
 2375    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2376        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2377    }
 2378
 2379    fn key_context_internal(
 2380        &self,
 2381        has_active_edit_prediction: bool,
 2382        window: &Window,
 2383        cx: &App,
 2384    ) -> KeyContext {
 2385        let mut key_context = KeyContext::new_with_defaults();
 2386        key_context.add("Editor");
 2387        let mode = match self.mode {
 2388            EditorMode::SingleLine { .. } => "single_line",
 2389            EditorMode::AutoHeight { .. } => "auto_height",
 2390            EditorMode::Minimap { .. } => "minimap",
 2391            EditorMode::Full { .. } => "full",
 2392        };
 2393
 2394        if EditorSettings::jupyter_enabled(cx) {
 2395            key_context.add("jupyter");
 2396        }
 2397
 2398        key_context.set("mode", mode);
 2399        if self.pending_rename.is_some() {
 2400            key_context.add("renaming");
 2401        }
 2402
 2403        match self.context_menu.borrow().as_ref() {
 2404            Some(CodeContextMenu::Completions(_)) => {
 2405                key_context.add("menu");
 2406                key_context.add("showing_completions");
 2407            }
 2408            Some(CodeContextMenu::CodeActions(_)) => {
 2409                key_context.add("menu");
 2410                key_context.add("showing_code_actions")
 2411            }
 2412            None => {}
 2413        }
 2414
 2415        if self.signature_help_state.has_multiple_signatures() {
 2416            key_context.add("showing_signature_help");
 2417        }
 2418
 2419        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2420        if !self.focus_handle(cx).contains_focused(window, cx)
 2421            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2422        {
 2423            for addon in self.addons.values() {
 2424                addon.extend_key_context(&mut key_context, cx)
 2425            }
 2426        }
 2427
 2428        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2429            if let Some(extension) = singleton_buffer
 2430                .read(cx)
 2431                .file()
 2432                .and_then(|file| file.path().extension()?.to_str())
 2433            {
 2434                key_context.set("extension", extension.to_string());
 2435            }
 2436        } else {
 2437            key_context.add("multibuffer");
 2438        }
 2439
 2440        if has_active_edit_prediction {
 2441            if self.edit_prediction_in_conflict() {
 2442                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2443            } else {
 2444                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2445                key_context.add("copilot_suggestion");
 2446            }
 2447        }
 2448
 2449        if self.selection_mark_mode {
 2450            key_context.add("selection_mode");
 2451        }
 2452
 2453        key_context
 2454    }
 2455
 2456    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2457        if self.mouse_cursor_hidden {
 2458            self.mouse_cursor_hidden = false;
 2459            cx.notify();
 2460        }
 2461    }
 2462
 2463    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2464        let hide_mouse_cursor = match origin {
 2465            HideMouseCursorOrigin::TypingAction => {
 2466                matches!(
 2467                    self.hide_mouse_mode,
 2468                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2469                )
 2470            }
 2471            HideMouseCursorOrigin::MovementAction => {
 2472                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2473            }
 2474        };
 2475        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2476            self.mouse_cursor_hidden = hide_mouse_cursor;
 2477            cx.notify();
 2478        }
 2479    }
 2480
 2481    pub fn edit_prediction_in_conflict(&self) -> bool {
 2482        if !self.show_edit_predictions_in_menu() {
 2483            return false;
 2484        }
 2485
 2486        let showing_completions = self
 2487            .context_menu
 2488            .borrow()
 2489            .as_ref()
 2490            .map_or(false, |context| {
 2491                matches!(context, CodeContextMenu::Completions(_))
 2492            });
 2493
 2494        showing_completions
 2495            || self.edit_prediction_requires_modifier()
 2496            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2497            // bindings to insert tab characters.
 2498            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2499    }
 2500
 2501    pub fn accept_edit_prediction_keybind(
 2502        &self,
 2503        accept_partial: bool,
 2504        window: &Window,
 2505        cx: &App,
 2506    ) -> AcceptEditPredictionBinding {
 2507        let key_context = self.key_context_internal(true, window, cx);
 2508        let in_conflict = self.edit_prediction_in_conflict();
 2509
 2510        let bindings = if accept_partial {
 2511            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2512        } else {
 2513            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2514        };
 2515
 2516        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2517        // just the first one.
 2518        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2519            !in_conflict
 2520                || binding
 2521                    .keystrokes()
 2522                    .first()
 2523                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2524        }))
 2525    }
 2526
 2527    pub fn new_file(
 2528        workspace: &mut Workspace,
 2529        _: &workspace::NewFile,
 2530        window: &mut Window,
 2531        cx: &mut Context<Workspace>,
 2532    ) {
 2533        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2534            "Failed to create buffer",
 2535            window,
 2536            cx,
 2537            |e, _, _| match e.error_code() {
 2538                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2539                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2540                e.error_tag("required").unwrap_or("the latest version")
 2541            )),
 2542                _ => None,
 2543            },
 2544        );
 2545    }
 2546
 2547    pub fn new_in_workspace(
 2548        workspace: &mut Workspace,
 2549        window: &mut Window,
 2550        cx: &mut Context<Workspace>,
 2551    ) -> Task<Result<Entity<Editor>>> {
 2552        let project = workspace.project().clone();
 2553        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2554
 2555        cx.spawn_in(window, async move |workspace, cx| {
 2556            let buffer = create.await?;
 2557            workspace.update_in(cx, |workspace, window, cx| {
 2558                let editor =
 2559                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2560                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2561                editor
 2562            })
 2563        })
 2564    }
 2565
 2566    fn new_file_vertical(
 2567        workspace: &mut Workspace,
 2568        _: &workspace::NewFileSplitVertical,
 2569        window: &mut Window,
 2570        cx: &mut Context<Workspace>,
 2571    ) {
 2572        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2573    }
 2574
 2575    fn new_file_horizontal(
 2576        workspace: &mut Workspace,
 2577        _: &workspace::NewFileSplitHorizontal,
 2578        window: &mut Window,
 2579        cx: &mut Context<Workspace>,
 2580    ) {
 2581        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2582    }
 2583
 2584    fn new_file_in_direction(
 2585        workspace: &mut Workspace,
 2586        direction: SplitDirection,
 2587        window: &mut Window,
 2588        cx: &mut Context<Workspace>,
 2589    ) {
 2590        let project = workspace.project().clone();
 2591        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2592
 2593        cx.spawn_in(window, async move |workspace, cx| {
 2594            let buffer = create.await?;
 2595            workspace.update_in(cx, move |workspace, window, cx| {
 2596                workspace.split_item(
 2597                    direction,
 2598                    Box::new(
 2599                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2600                    ),
 2601                    window,
 2602                    cx,
 2603                )
 2604            })?;
 2605            anyhow::Ok(())
 2606        })
 2607        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2608            match e.error_code() {
 2609                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2610                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2611                e.error_tag("required").unwrap_or("the latest version")
 2612            )),
 2613                _ => None,
 2614            }
 2615        });
 2616    }
 2617
 2618    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2619        self.leader_id
 2620    }
 2621
 2622    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2623        &self.buffer
 2624    }
 2625
 2626    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2627        self.workspace.as_ref()?.0.upgrade()
 2628    }
 2629
 2630    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2631        self.buffer().read(cx).title(cx)
 2632    }
 2633
 2634    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2635        let git_blame_gutter_max_author_length = self
 2636            .render_git_blame_gutter(cx)
 2637            .then(|| {
 2638                if let Some(blame) = self.blame.as_ref() {
 2639                    let max_author_length =
 2640                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2641                    Some(max_author_length)
 2642                } else {
 2643                    None
 2644                }
 2645            })
 2646            .flatten();
 2647
 2648        EditorSnapshot {
 2649            mode: self.mode.clone(),
 2650            show_gutter: self.show_gutter,
 2651            show_line_numbers: self.show_line_numbers,
 2652            show_git_diff_gutter: self.show_git_diff_gutter,
 2653            show_code_actions: self.show_code_actions,
 2654            show_runnables: self.show_runnables,
 2655            show_breakpoints: self.show_breakpoints,
 2656            git_blame_gutter_max_author_length,
 2657            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2658            scroll_anchor: self.scroll_manager.anchor(),
 2659            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2660            placeholder_text: self.placeholder_text.clone(),
 2661            is_focused: self.focus_handle.is_focused(window),
 2662            current_line_highlight: self
 2663                .current_line_highlight
 2664                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2665            gutter_hovered: self.gutter_hovered,
 2666        }
 2667    }
 2668
 2669    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2670        self.buffer.read(cx).language_at(point, cx)
 2671    }
 2672
 2673    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2674        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2675    }
 2676
 2677    pub fn active_excerpt(
 2678        &self,
 2679        cx: &App,
 2680    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2681        self.buffer
 2682            .read(cx)
 2683            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2684    }
 2685
 2686    pub fn mode(&self) -> &EditorMode {
 2687        &self.mode
 2688    }
 2689
 2690    pub fn set_mode(&mut self, mode: EditorMode) {
 2691        self.mode = mode;
 2692    }
 2693
 2694    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2695        self.collaboration_hub.as_deref()
 2696    }
 2697
 2698    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2699        self.collaboration_hub = Some(hub);
 2700    }
 2701
 2702    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2703        self.in_project_search = in_project_search;
 2704    }
 2705
 2706    pub fn set_custom_context_menu(
 2707        &mut self,
 2708        f: impl 'static
 2709        + Fn(
 2710            &mut Self,
 2711            DisplayPoint,
 2712            &mut Window,
 2713            &mut Context<Self>,
 2714        ) -> Option<Entity<ui::ContextMenu>>,
 2715    ) {
 2716        self.custom_context_menu = Some(Box::new(f))
 2717    }
 2718
 2719    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2720        self.completion_provider = provider;
 2721    }
 2722
 2723    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2724        self.semantics_provider.clone()
 2725    }
 2726
 2727    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2728        self.semantics_provider = provider;
 2729    }
 2730
 2731    pub fn set_edit_prediction_provider<T>(
 2732        &mut self,
 2733        provider: Option<Entity<T>>,
 2734        window: &mut Window,
 2735        cx: &mut Context<Self>,
 2736    ) where
 2737        T: EditPredictionProvider,
 2738    {
 2739        self.edit_prediction_provider =
 2740            provider.map(|provider| RegisteredInlineCompletionProvider {
 2741                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2742                    if this.focus_handle.is_focused(window) {
 2743                        this.update_visible_inline_completion(window, cx);
 2744                    }
 2745                }),
 2746                provider: Arc::new(provider),
 2747            });
 2748        self.update_edit_prediction_settings(cx);
 2749        self.refresh_inline_completion(false, false, window, cx);
 2750    }
 2751
 2752    pub fn placeholder_text(&self) -> Option<&str> {
 2753        self.placeholder_text.as_deref()
 2754    }
 2755
 2756    pub fn set_placeholder_text(
 2757        &mut self,
 2758        placeholder_text: impl Into<Arc<str>>,
 2759        cx: &mut Context<Self>,
 2760    ) {
 2761        let placeholder_text = Some(placeholder_text.into());
 2762        if self.placeholder_text != placeholder_text {
 2763            self.placeholder_text = placeholder_text;
 2764            cx.notify();
 2765        }
 2766    }
 2767
 2768    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2769        self.cursor_shape = cursor_shape;
 2770
 2771        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2772        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2773
 2774        cx.notify();
 2775    }
 2776
 2777    pub fn set_current_line_highlight(
 2778        &mut self,
 2779        current_line_highlight: Option<CurrentLineHighlight>,
 2780    ) {
 2781        self.current_line_highlight = current_line_highlight;
 2782    }
 2783
 2784    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2785        self.collapse_matches = collapse_matches;
 2786    }
 2787
 2788    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2789        let buffers = self.buffer.read(cx).all_buffers();
 2790        let Some(project) = self.project.as_ref() else {
 2791            return;
 2792        };
 2793        project.update(cx, |project, cx| {
 2794            for buffer in buffers {
 2795                self.registered_buffers
 2796                    .entry(buffer.read(cx).remote_id())
 2797                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2798            }
 2799        })
 2800    }
 2801
 2802    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2803        if self.collapse_matches {
 2804            return range.start..range.start;
 2805        }
 2806        range.clone()
 2807    }
 2808
 2809    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2810        if self.display_map.read(cx).clip_at_line_ends != clip {
 2811            self.display_map
 2812                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2813        }
 2814    }
 2815
 2816    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2817        self.input_enabled = input_enabled;
 2818    }
 2819
 2820    pub fn set_inline_completions_hidden_for_vim_mode(
 2821        &mut self,
 2822        hidden: bool,
 2823        window: &mut Window,
 2824        cx: &mut Context<Self>,
 2825    ) {
 2826        if hidden != self.inline_completions_hidden_for_vim_mode {
 2827            self.inline_completions_hidden_for_vim_mode = hidden;
 2828            if hidden {
 2829                self.update_visible_inline_completion(window, cx);
 2830            } else {
 2831                self.refresh_inline_completion(true, false, window, cx);
 2832            }
 2833        }
 2834    }
 2835
 2836    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2837        self.menu_inline_completions_policy = value;
 2838    }
 2839
 2840    pub fn set_autoindent(&mut self, autoindent: bool) {
 2841        if autoindent {
 2842            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2843        } else {
 2844            self.autoindent_mode = None;
 2845        }
 2846    }
 2847
 2848    pub fn read_only(&self, cx: &App) -> bool {
 2849        self.read_only || self.buffer.read(cx).read_only()
 2850    }
 2851
 2852    pub fn set_read_only(&mut self, read_only: bool) {
 2853        self.read_only = read_only;
 2854    }
 2855
 2856    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2857        self.use_autoclose = autoclose;
 2858    }
 2859
 2860    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2861        self.use_auto_surround = auto_surround;
 2862    }
 2863
 2864    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2865        self.auto_replace_emoji_shortcode = auto_replace;
 2866    }
 2867
 2868    pub fn toggle_edit_predictions(
 2869        &mut self,
 2870        _: &ToggleEditPrediction,
 2871        window: &mut Window,
 2872        cx: &mut Context<Self>,
 2873    ) {
 2874        if self.show_inline_completions_override.is_some() {
 2875            self.set_show_edit_predictions(None, window, cx);
 2876        } else {
 2877            let show_edit_predictions = !self.edit_predictions_enabled();
 2878            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2879        }
 2880    }
 2881
 2882    pub fn set_show_edit_predictions(
 2883        &mut self,
 2884        show_edit_predictions: Option<bool>,
 2885        window: &mut Window,
 2886        cx: &mut Context<Self>,
 2887    ) {
 2888        self.show_inline_completions_override = show_edit_predictions;
 2889        self.update_edit_prediction_settings(cx);
 2890
 2891        if let Some(false) = show_edit_predictions {
 2892            self.discard_inline_completion(false, cx);
 2893        } else {
 2894            self.refresh_inline_completion(false, true, window, cx);
 2895        }
 2896    }
 2897
 2898    fn inline_completions_disabled_in_scope(
 2899        &self,
 2900        buffer: &Entity<Buffer>,
 2901        buffer_position: language::Anchor,
 2902        cx: &App,
 2903    ) -> bool {
 2904        let snapshot = buffer.read(cx).snapshot();
 2905        let settings = snapshot.settings_at(buffer_position, cx);
 2906
 2907        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2908            return false;
 2909        };
 2910
 2911        scope.override_name().map_or(false, |scope_name| {
 2912            settings
 2913                .edit_predictions_disabled_in
 2914                .iter()
 2915                .any(|s| s == scope_name)
 2916        })
 2917    }
 2918
 2919    pub fn set_use_modal_editing(&mut self, to: bool) {
 2920        self.use_modal_editing = to;
 2921    }
 2922
 2923    pub fn use_modal_editing(&self) -> bool {
 2924        self.use_modal_editing
 2925    }
 2926
 2927    fn selections_did_change(
 2928        &mut self,
 2929        local: bool,
 2930        old_cursor_position: &Anchor,
 2931        effects: SelectionEffects,
 2932        window: &mut Window,
 2933        cx: &mut Context<Self>,
 2934    ) {
 2935        window.invalidate_character_coordinates();
 2936
 2937        // Copy selections to primary selection buffer
 2938        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2939        if local {
 2940            let selections = self.selections.all::<usize>(cx);
 2941            let buffer_handle = self.buffer.read(cx).read(cx);
 2942
 2943            let mut text = String::new();
 2944            for (index, selection) in selections.iter().enumerate() {
 2945                let text_for_selection = buffer_handle
 2946                    .text_for_range(selection.start..selection.end)
 2947                    .collect::<String>();
 2948
 2949                text.push_str(&text_for_selection);
 2950                if index != selections.len() - 1 {
 2951                    text.push('\n');
 2952                }
 2953            }
 2954
 2955            if !text.is_empty() {
 2956                cx.write_to_primary(ClipboardItem::new_string(text));
 2957            }
 2958        }
 2959
 2960        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2961            self.buffer.update(cx, |buffer, cx| {
 2962                buffer.set_active_selections(
 2963                    &self.selections.disjoint_anchors(),
 2964                    self.selections.line_mode,
 2965                    self.cursor_shape,
 2966                    cx,
 2967                )
 2968            });
 2969        }
 2970        let display_map = self
 2971            .display_map
 2972            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2973        let buffer = &display_map.buffer_snapshot;
 2974        if self.selections.count() == 1 {
 2975            self.add_selections_state = None;
 2976        }
 2977        self.select_next_state = None;
 2978        self.select_prev_state = None;
 2979        self.select_syntax_node_history.try_clear();
 2980        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2981        self.snippet_stack
 2982            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2983        self.take_rename(false, window, cx);
 2984
 2985        let newest_selection = self.selections.newest_anchor();
 2986        let new_cursor_position = newest_selection.head();
 2987        let selection_start = newest_selection.start;
 2988
 2989        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2990            self.push_to_nav_history(
 2991                *old_cursor_position,
 2992                Some(new_cursor_position.to_point(buffer)),
 2993                false,
 2994                effects.nav_history == Some(true),
 2995                cx,
 2996            );
 2997        }
 2998
 2999        if local {
 3000            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3001                if !self.registered_buffers.contains_key(&buffer_id) {
 3002                    if let Some(project) = self.project.as_ref() {
 3003                        project.update(cx, |project, cx| {
 3004                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3005                                return;
 3006                            };
 3007                            self.registered_buffers.insert(
 3008                                buffer_id,
 3009                                project.register_buffer_with_language_servers(&buffer, cx),
 3010                            );
 3011                        })
 3012                    }
 3013                }
 3014            }
 3015
 3016            let mut context_menu = self.context_menu.borrow_mut();
 3017            let completion_menu = match context_menu.as_ref() {
 3018                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3019                Some(CodeContextMenu::CodeActions(_)) => {
 3020                    *context_menu = None;
 3021                    None
 3022                }
 3023                None => None,
 3024            };
 3025            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3026            drop(context_menu);
 3027
 3028            if effects.completions {
 3029                if let Some(completion_position) = completion_position {
 3030                    let start_offset = selection_start.to_offset(buffer);
 3031                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3032                    let continue_showing = if position_matches {
 3033                        if self.snippet_stack.is_empty() {
 3034                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3035                        } else {
 3036                            // Snippet choices can be shown even when the cursor is in whitespace.
 3037                            // Dismissing the menu with actions like backspace is handled by
 3038                            // invalidation regions.
 3039                            true
 3040                        }
 3041                    } else {
 3042                        false
 3043                    };
 3044
 3045                    if continue_showing {
 3046                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3047                    } else {
 3048                        self.hide_context_menu(window, cx);
 3049                    }
 3050                }
 3051            }
 3052
 3053            hide_hover(self, cx);
 3054
 3055            if old_cursor_position.to_display_point(&display_map).row()
 3056                != new_cursor_position.to_display_point(&display_map).row()
 3057            {
 3058                self.available_code_actions.take();
 3059            }
 3060            self.refresh_code_actions(window, cx);
 3061            self.refresh_document_highlights(cx);
 3062            self.refresh_selected_text_highlights(false, window, cx);
 3063            refresh_matching_bracket_highlights(self, window, cx);
 3064            self.update_visible_inline_completion(window, cx);
 3065            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3066            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3067            self.inline_blame_popover.take();
 3068            if self.git_blame_inline_enabled {
 3069                self.start_inline_blame_timer(window, cx);
 3070            }
 3071        }
 3072
 3073        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3074        cx.emit(EditorEvent::SelectionsChanged { local });
 3075
 3076        let selections = &self.selections.disjoint;
 3077        if selections.len() == 1 {
 3078            cx.emit(SearchEvent::ActiveMatchChanged)
 3079        }
 3080        if local {
 3081            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3082                let inmemory_selections = selections
 3083                    .iter()
 3084                    .map(|s| {
 3085                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3086                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3087                    })
 3088                    .collect();
 3089                self.update_restoration_data(cx, |data| {
 3090                    data.selections = inmemory_selections;
 3091                });
 3092
 3093                if WorkspaceSettings::get(None, cx).restore_on_startup
 3094                    != RestoreOnStartupBehavior::None
 3095                {
 3096                    if let Some(workspace_id) =
 3097                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3098                    {
 3099                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3100                        let selections = selections.clone();
 3101                        let background_executor = cx.background_executor().clone();
 3102                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3103                        self.serialize_selections = cx.background_spawn(async move {
 3104                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3105                            let db_selections = selections
 3106                                .iter()
 3107                                .map(|selection| {
 3108                                    (
 3109                                        selection.start.to_offset(&snapshot),
 3110                                        selection.end.to_offset(&snapshot),
 3111                                    )
 3112                                })
 3113                                .collect();
 3114
 3115                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3116                                .await
 3117                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3118                                .log_err();
 3119                        });
 3120                    }
 3121                }
 3122            }
 3123        }
 3124
 3125        cx.notify();
 3126    }
 3127
 3128    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3129        use text::ToOffset as _;
 3130        use text::ToPoint as _;
 3131
 3132        if self.mode.is_minimap()
 3133            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3134        {
 3135            return;
 3136        }
 3137
 3138        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3139            return;
 3140        };
 3141
 3142        let snapshot = singleton.read(cx).snapshot();
 3143        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3144            let display_snapshot = display_map.snapshot(cx);
 3145
 3146            display_snapshot
 3147                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3148                .map(|fold| {
 3149                    fold.range.start.text_anchor.to_point(&snapshot)
 3150                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3151                })
 3152                .collect()
 3153        });
 3154        self.update_restoration_data(cx, |data| {
 3155            data.folds = inmemory_folds;
 3156        });
 3157
 3158        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3159            return;
 3160        };
 3161        let background_executor = cx.background_executor().clone();
 3162        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3163        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3164            display_map
 3165                .snapshot(cx)
 3166                .folds_in_range(0..snapshot.len())
 3167                .map(|fold| {
 3168                    (
 3169                        fold.range.start.text_anchor.to_offset(&snapshot),
 3170                        fold.range.end.text_anchor.to_offset(&snapshot),
 3171                    )
 3172                })
 3173                .collect()
 3174        });
 3175        self.serialize_folds = cx.background_spawn(async move {
 3176            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3177            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3178                .await
 3179                .with_context(|| {
 3180                    format!(
 3181                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3182                    )
 3183                })
 3184                .log_err();
 3185        });
 3186    }
 3187
 3188    pub fn sync_selections(
 3189        &mut self,
 3190        other: Entity<Editor>,
 3191        cx: &mut Context<Self>,
 3192    ) -> gpui::Subscription {
 3193        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3194        self.selections.change_with(cx, |selections| {
 3195            selections.select_anchors(other_selections);
 3196        });
 3197
 3198        let other_subscription =
 3199            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3200                EditorEvent::SelectionsChanged { local: true } => {
 3201                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3202                    if other_selections.is_empty() {
 3203                        return;
 3204                    }
 3205                    this.selections.change_with(cx, |selections| {
 3206                        selections.select_anchors(other_selections);
 3207                    });
 3208                }
 3209                _ => {}
 3210            });
 3211
 3212        let this_subscription =
 3213            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3214                EditorEvent::SelectionsChanged { local: true } => {
 3215                    let these_selections = this.selections.disjoint.to_vec();
 3216                    if these_selections.is_empty() {
 3217                        return;
 3218                    }
 3219                    other.update(cx, |other_editor, cx| {
 3220                        other_editor.selections.change_with(cx, |selections| {
 3221                            selections.select_anchors(these_selections);
 3222                        })
 3223                    });
 3224                }
 3225                _ => {}
 3226            });
 3227
 3228        Subscription::join(other_subscription, this_subscription)
 3229    }
 3230
 3231    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3232    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3233    /// effects of selection change occur at the end of the transaction.
 3234    pub fn change_selections<R>(
 3235        &mut self,
 3236        effects: SelectionEffects,
 3237        window: &mut Window,
 3238        cx: &mut Context<Self>,
 3239        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3240    ) -> R {
 3241        if let Some(state) = &mut self.deferred_selection_effects_state {
 3242            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3243            state.effects.completions = effects.completions;
 3244            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3245            let (changed, result) = self.selections.change_with(cx, change);
 3246            state.changed |= changed;
 3247            return result;
 3248        }
 3249        let mut state = DeferredSelectionEffectsState {
 3250            changed: false,
 3251            effects,
 3252            old_cursor_position: self.selections.newest_anchor().head(),
 3253            history_entry: SelectionHistoryEntry {
 3254                selections: self.selections.disjoint_anchors(),
 3255                select_next_state: self.select_next_state.clone(),
 3256                select_prev_state: self.select_prev_state.clone(),
 3257                add_selections_state: self.add_selections_state.clone(),
 3258            },
 3259        };
 3260        let (changed, result) = self.selections.change_with(cx, change);
 3261        state.changed = state.changed || changed;
 3262        if self.defer_selection_effects {
 3263            self.deferred_selection_effects_state = Some(state);
 3264        } else {
 3265            self.apply_selection_effects(state, window, cx);
 3266        }
 3267        result
 3268    }
 3269
 3270    /// Defers the effects of selection change, so that the effects of multiple calls to
 3271    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3272    /// to selection history and the state of popovers based on selection position aren't
 3273    /// erroneously updated.
 3274    pub fn with_selection_effects_deferred<R>(
 3275        &mut self,
 3276        window: &mut Window,
 3277        cx: &mut Context<Self>,
 3278        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3279    ) -> R {
 3280        let already_deferred = self.defer_selection_effects;
 3281        self.defer_selection_effects = true;
 3282        let result = update(self, window, cx);
 3283        if !already_deferred {
 3284            self.defer_selection_effects = false;
 3285            if let Some(state) = self.deferred_selection_effects_state.take() {
 3286                self.apply_selection_effects(state, window, cx);
 3287            }
 3288        }
 3289        result
 3290    }
 3291
 3292    fn apply_selection_effects(
 3293        &mut self,
 3294        state: DeferredSelectionEffectsState,
 3295        window: &mut Window,
 3296        cx: &mut Context<Self>,
 3297    ) {
 3298        if state.changed {
 3299            self.selection_history.push(state.history_entry);
 3300
 3301            if let Some(autoscroll) = state.effects.scroll {
 3302                self.request_autoscroll(autoscroll, cx);
 3303            }
 3304
 3305            let old_cursor_position = &state.old_cursor_position;
 3306
 3307            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3308
 3309            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3310                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3311            }
 3312        }
 3313    }
 3314
 3315    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3316    where
 3317        I: IntoIterator<Item = (Range<S>, T)>,
 3318        S: ToOffset,
 3319        T: Into<Arc<str>>,
 3320    {
 3321        if self.read_only(cx) {
 3322            return;
 3323        }
 3324
 3325        self.buffer
 3326            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3327    }
 3328
 3329    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3330    where
 3331        I: IntoIterator<Item = (Range<S>, T)>,
 3332        S: ToOffset,
 3333        T: Into<Arc<str>>,
 3334    {
 3335        if self.read_only(cx) {
 3336            return;
 3337        }
 3338
 3339        self.buffer.update(cx, |buffer, cx| {
 3340            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3341        });
 3342    }
 3343
 3344    pub fn edit_with_block_indent<I, S, T>(
 3345        &mut self,
 3346        edits: I,
 3347        original_indent_columns: Vec<Option<u32>>,
 3348        cx: &mut Context<Self>,
 3349    ) where
 3350        I: IntoIterator<Item = (Range<S>, T)>,
 3351        S: ToOffset,
 3352        T: Into<Arc<str>>,
 3353    {
 3354        if self.read_only(cx) {
 3355            return;
 3356        }
 3357
 3358        self.buffer.update(cx, |buffer, cx| {
 3359            buffer.edit(
 3360                edits,
 3361                Some(AutoindentMode::Block {
 3362                    original_indent_columns,
 3363                }),
 3364                cx,
 3365            )
 3366        });
 3367    }
 3368
 3369    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3370        self.hide_context_menu(window, cx);
 3371
 3372        match phase {
 3373            SelectPhase::Begin {
 3374                position,
 3375                add,
 3376                click_count,
 3377            } => self.begin_selection(position, add, click_count, window, cx),
 3378            SelectPhase::BeginColumnar {
 3379                position,
 3380                goal_column,
 3381                reset,
 3382                mode,
 3383            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3384            SelectPhase::Extend {
 3385                position,
 3386                click_count,
 3387            } => self.extend_selection(position, click_count, window, cx),
 3388            SelectPhase::Update {
 3389                position,
 3390                goal_column,
 3391                scroll_delta,
 3392            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3393            SelectPhase::End => self.end_selection(window, cx),
 3394        }
 3395    }
 3396
 3397    fn extend_selection(
 3398        &mut self,
 3399        position: DisplayPoint,
 3400        click_count: usize,
 3401        window: &mut Window,
 3402        cx: &mut Context<Self>,
 3403    ) {
 3404        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3405        let tail = self.selections.newest::<usize>(cx).tail();
 3406        self.begin_selection(position, false, click_count, window, cx);
 3407
 3408        let position = position.to_offset(&display_map, Bias::Left);
 3409        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3410
 3411        let mut pending_selection = self
 3412            .selections
 3413            .pending_anchor()
 3414            .expect("extend_selection not called with pending selection");
 3415        if position >= tail {
 3416            pending_selection.start = tail_anchor;
 3417        } else {
 3418            pending_selection.end = tail_anchor;
 3419            pending_selection.reversed = true;
 3420        }
 3421
 3422        let mut pending_mode = self.selections.pending_mode().unwrap();
 3423        match &mut pending_mode {
 3424            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3425            _ => {}
 3426        }
 3427
 3428        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3429            SelectionEffects::scroll(Autoscroll::fit())
 3430        } else {
 3431            SelectionEffects::no_scroll()
 3432        };
 3433
 3434        self.change_selections(effects, window, cx, |s| {
 3435            s.set_pending(pending_selection, pending_mode)
 3436        });
 3437    }
 3438
 3439    fn begin_selection(
 3440        &mut self,
 3441        position: DisplayPoint,
 3442        add: bool,
 3443        click_count: usize,
 3444        window: &mut Window,
 3445        cx: &mut Context<Self>,
 3446    ) {
 3447        if !self.focus_handle.is_focused(window) {
 3448            self.last_focused_descendant = None;
 3449            window.focus(&self.focus_handle);
 3450        }
 3451
 3452        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3453        let buffer = &display_map.buffer_snapshot;
 3454        let position = display_map.clip_point(position, Bias::Left);
 3455
 3456        let start;
 3457        let end;
 3458        let mode;
 3459        let mut auto_scroll;
 3460        match click_count {
 3461            1 => {
 3462                start = buffer.anchor_before(position.to_point(&display_map));
 3463                end = start;
 3464                mode = SelectMode::Character;
 3465                auto_scroll = true;
 3466            }
 3467            2 => {
 3468                let position = display_map
 3469                    .clip_point(position, Bias::Left)
 3470                    .to_offset(&display_map, Bias::Left);
 3471                let (range, _) = buffer.surrounding_word(position, false);
 3472                start = buffer.anchor_before(range.start);
 3473                end = buffer.anchor_before(range.end);
 3474                mode = SelectMode::Word(start..end);
 3475                auto_scroll = true;
 3476            }
 3477            3 => {
 3478                let position = display_map
 3479                    .clip_point(position, Bias::Left)
 3480                    .to_point(&display_map);
 3481                let line_start = display_map.prev_line_boundary(position).0;
 3482                let next_line_start = buffer.clip_point(
 3483                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3484                    Bias::Left,
 3485                );
 3486                start = buffer.anchor_before(line_start);
 3487                end = buffer.anchor_before(next_line_start);
 3488                mode = SelectMode::Line(start..end);
 3489                auto_scroll = true;
 3490            }
 3491            _ => {
 3492                start = buffer.anchor_before(0);
 3493                end = buffer.anchor_before(buffer.len());
 3494                mode = SelectMode::All;
 3495                auto_scroll = false;
 3496            }
 3497        }
 3498        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3499
 3500        let point_to_delete: Option<usize> = {
 3501            let selected_points: Vec<Selection<Point>> =
 3502                self.selections.disjoint_in_range(start..end, cx);
 3503
 3504            if !add || click_count > 1 {
 3505                None
 3506            } else if !selected_points.is_empty() {
 3507                Some(selected_points[0].id)
 3508            } else {
 3509                let clicked_point_already_selected =
 3510                    self.selections.disjoint.iter().find(|selection| {
 3511                        selection.start.to_point(buffer) == start.to_point(buffer)
 3512                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3513                    });
 3514
 3515                clicked_point_already_selected.map(|selection| selection.id)
 3516            }
 3517        };
 3518
 3519        let selections_count = self.selections.count();
 3520        let effects = if auto_scroll {
 3521            SelectionEffects::default()
 3522        } else {
 3523            SelectionEffects::no_scroll()
 3524        };
 3525
 3526        self.change_selections(effects, window, cx, |s| {
 3527            if let Some(point_to_delete) = point_to_delete {
 3528                s.delete(point_to_delete);
 3529
 3530                if selections_count == 1 {
 3531                    s.set_pending_anchor_range(start..end, mode);
 3532                }
 3533            } else {
 3534                if !add {
 3535                    s.clear_disjoint();
 3536                }
 3537
 3538                s.set_pending_anchor_range(start..end, mode);
 3539            }
 3540        });
 3541    }
 3542
 3543    fn begin_columnar_selection(
 3544        &mut self,
 3545        position: DisplayPoint,
 3546        goal_column: u32,
 3547        reset: bool,
 3548        mode: ColumnarMode,
 3549        window: &mut Window,
 3550        cx: &mut Context<Self>,
 3551    ) {
 3552        if !self.focus_handle.is_focused(window) {
 3553            self.last_focused_descendant = None;
 3554            window.focus(&self.focus_handle);
 3555        }
 3556
 3557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3558
 3559        if reset {
 3560            let pointer_position = display_map
 3561                .buffer_snapshot
 3562                .anchor_before(position.to_point(&display_map));
 3563
 3564            self.change_selections(
 3565                SelectionEffects::scroll(Autoscroll::newest()),
 3566                window,
 3567                cx,
 3568                |s| {
 3569                    s.clear_disjoint();
 3570                    s.set_pending_anchor_range(
 3571                        pointer_position..pointer_position,
 3572                        SelectMode::Character,
 3573                    );
 3574                },
 3575            );
 3576        };
 3577
 3578        let tail = self.selections.newest::<Point>(cx).tail();
 3579        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3580        self.columnar_selection_state = match mode {
 3581            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3582                selection_tail: selection_anchor,
 3583                display_point: if reset {
 3584                    if position.column() != goal_column {
 3585                        Some(DisplayPoint::new(position.row(), goal_column))
 3586                    } else {
 3587                        None
 3588                    }
 3589                } else {
 3590                    None
 3591                },
 3592            }),
 3593            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3594                selection_tail: selection_anchor,
 3595            }),
 3596        };
 3597
 3598        if !reset {
 3599            self.select_columns(position, goal_column, &display_map, window, cx);
 3600        }
 3601    }
 3602
 3603    fn update_selection(
 3604        &mut self,
 3605        position: DisplayPoint,
 3606        goal_column: u32,
 3607        scroll_delta: gpui::Point<f32>,
 3608        window: &mut Window,
 3609        cx: &mut Context<Self>,
 3610    ) {
 3611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3612
 3613        if self.columnar_selection_state.is_some() {
 3614            self.select_columns(position, goal_column, &display_map, window, cx);
 3615        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3616            let buffer = &display_map.buffer_snapshot;
 3617            let head;
 3618            let tail;
 3619            let mode = self.selections.pending_mode().unwrap();
 3620            match &mode {
 3621                SelectMode::Character => {
 3622                    head = position.to_point(&display_map);
 3623                    tail = pending.tail().to_point(buffer);
 3624                }
 3625                SelectMode::Word(original_range) => {
 3626                    let offset = display_map
 3627                        .clip_point(position, Bias::Left)
 3628                        .to_offset(&display_map, Bias::Left);
 3629                    let original_range = original_range.to_offset(buffer);
 3630
 3631                    let head_offset = if buffer.is_inside_word(offset, false)
 3632                        || original_range.contains(&offset)
 3633                    {
 3634                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3635                        if word_range.start < original_range.start {
 3636                            word_range.start
 3637                        } else {
 3638                            word_range.end
 3639                        }
 3640                    } else {
 3641                        offset
 3642                    };
 3643
 3644                    head = head_offset.to_point(buffer);
 3645                    if head_offset <= original_range.start {
 3646                        tail = original_range.end.to_point(buffer);
 3647                    } else {
 3648                        tail = original_range.start.to_point(buffer);
 3649                    }
 3650                }
 3651                SelectMode::Line(original_range) => {
 3652                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3653
 3654                    let position = display_map
 3655                        .clip_point(position, Bias::Left)
 3656                        .to_point(&display_map);
 3657                    let line_start = display_map.prev_line_boundary(position).0;
 3658                    let next_line_start = buffer.clip_point(
 3659                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3660                        Bias::Left,
 3661                    );
 3662
 3663                    if line_start < original_range.start {
 3664                        head = line_start
 3665                    } else {
 3666                        head = next_line_start
 3667                    }
 3668
 3669                    if head <= original_range.start {
 3670                        tail = original_range.end;
 3671                    } else {
 3672                        tail = original_range.start;
 3673                    }
 3674                }
 3675                SelectMode::All => {
 3676                    return;
 3677                }
 3678            };
 3679
 3680            if head < tail {
 3681                pending.start = buffer.anchor_before(head);
 3682                pending.end = buffer.anchor_before(tail);
 3683                pending.reversed = true;
 3684            } else {
 3685                pending.start = buffer.anchor_before(tail);
 3686                pending.end = buffer.anchor_before(head);
 3687                pending.reversed = false;
 3688            }
 3689
 3690            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3691                s.set_pending(pending, mode);
 3692            });
 3693        } else {
 3694            log::error!("update_selection dispatched with no pending selection");
 3695            return;
 3696        }
 3697
 3698        self.apply_scroll_delta(scroll_delta, window, cx);
 3699        cx.notify();
 3700    }
 3701
 3702    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3703        self.columnar_selection_state.take();
 3704        if self.selections.pending_anchor().is_some() {
 3705            let selections = self.selections.all::<usize>(cx);
 3706            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3707                s.select(selections);
 3708                s.clear_pending();
 3709            });
 3710        }
 3711    }
 3712
 3713    fn select_columns(
 3714        &mut self,
 3715        head: DisplayPoint,
 3716        goal_column: u32,
 3717        display_map: &DisplaySnapshot,
 3718        window: &mut Window,
 3719        cx: &mut Context<Self>,
 3720    ) {
 3721        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3722            return;
 3723        };
 3724
 3725        let tail = match columnar_state {
 3726            ColumnarSelectionState::FromMouse {
 3727                selection_tail,
 3728                display_point,
 3729            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3730            ColumnarSelectionState::FromSelection { selection_tail } => {
 3731                selection_tail.to_display_point(&display_map)
 3732            }
 3733        };
 3734
 3735        let start_row = cmp::min(tail.row(), head.row());
 3736        let end_row = cmp::max(tail.row(), head.row());
 3737        let start_column = cmp::min(tail.column(), goal_column);
 3738        let end_column = cmp::max(tail.column(), goal_column);
 3739        let reversed = start_column < tail.column();
 3740
 3741        let selection_ranges = (start_row.0..=end_row.0)
 3742            .map(DisplayRow)
 3743            .filter_map(|row| {
 3744                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3745                    || start_column <= display_map.line_len(row))
 3746                    && !display_map.is_block_line(row)
 3747                {
 3748                    let start = display_map
 3749                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3750                        .to_point(display_map);
 3751                    let end = display_map
 3752                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3753                        .to_point(display_map);
 3754                    if reversed {
 3755                        Some(end..start)
 3756                    } else {
 3757                        Some(start..end)
 3758                    }
 3759                } else {
 3760                    None
 3761                }
 3762            })
 3763            .collect::<Vec<_>>();
 3764
 3765        let ranges = match columnar_state {
 3766            ColumnarSelectionState::FromMouse { .. } => {
 3767                let mut non_empty_ranges = selection_ranges
 3768                    .iter()
 3769                    .filter(|selection_range| selection_range.start != selection_range.end)
 3770                    .peekable();
 3771                if non_empty_ranges.peek().is_some() {
 3772                    non_empty_ranges.cloned().collect()
 3773                } else {
 3774                    selection_ranges
 3775                }
 3776            }
 3777            _ => selection_ranges,
 3778        };
 3779
 3780        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3781            s.select_ranges(ranges);
 3782        });
 3783        cx.notify();
 3784    }
 3785
 3786    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3787        self.selections
 3788            .all_adjusted(cx)
 3789            .iter()
 3790            .any(|selection| !selection.is_empty())
 3791    }
 3792
 3793    pub fn has_pending_nonempty_selection(&self) -> bool {
 3794        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3795            Some(Selection { start, end, .. }) => start != end,
 3796            None => false,
 3797        };
 3798
 3799        pending_nonempty_selection
 3800            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3801    }
 3802
 3803    pub fn has_pending_selection(&self) -> bool {
 3804        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3805    }
 3806
 3807    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3808        self.selection_mark_mode = false;
 3809        self.selection_drag_state = SelectionDragState::None;
 3810
 3811        if self.clear_expanded_diff_hunks(cx) {
 3812            cx.notify();
 3813            return;
 3814        }
 3815        if self.dismiss_menus_and_popups(true, window, cx) {
 3816            return;
 3817        }
 3818
 3819        if self.mode.is_full()
 3820            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3821        {
 3822            return;
 3823        }
 3824
 3825        cx.propagate();
 3826    }
 3827
 3828    pub fn dismiss_menus_and_popups(
 3829        &mut self,
 3830        is_user_requested: bool,
 3831        window: &mut Window,
 3832        cx: &mut Context<Self>,
 3833    ) -> bool {
 3834        if self.take_rename(false, window, cx).is_some() {
 3835            return true;
 3836        }
 3837
 3838        if hide_hover(self, cx) {
 3839            return true;
 3840        }
 3841
 3842        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3843            return true;
 3844        }
 3845
 3846        if self.hide_context_menu(window, cx).is_some() {
 3847            return true;
 3848        }
 3849
 3850        if self.mouse_context_menu.take().is_some() {
 3851            return true;
 3852        }
 3853
 3854        if is_user_requested && self.discard_inline_completion(true, cx) {
 3855            return true;
 3856        }
 3857
 3858        if self.snippet_stack.pop().is_some() {
 3859            return true;
 3860        }
 3861
 3862        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3863            self.dismiss_diagnostics(cx);
 3864            return true;
 3865        }
 3866
 3867        false
 3868    }
 3869
 3870    fn linked_editing_ranges_for(
 3871        &self,
 3872        selection: Range<text::Anchor>,
 3873        cx: &App,
 3874    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3875        if self.linked_edit_ranges.is_empty() {
 3876            return None;
 3877        }
 3878        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3879            selection.end.buffer_id.and_then(|end_buffer_id| {
 3880                if selection.start.buffer_id != Some(end_buffer_id) {
 3881                    return None;
 3882                }
 3883                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3884                let snapshot = buffer.read(cx).snapshot();
 3885                self.linked_edit_ranges
 3886                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3887                    .map(|ranges| (ranges, snapshot, buffer))
 3888            })?;
 3889        use text::ToOffset as TO;
 3890        // find offset from the start of current range to current cursor position
 3891        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3892
 3893        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3894        let start_difference = start_offset - start_byte_offset;
 3895        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3896        let end_difference = end_offset - start_byte_offset;
 3897        // Current range has associated linked ranges.
 3898        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3899        for range in linked_ranges.iter() {
 3900            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3901            let end_offset = start_offset + end_difference;
 3902            let start_offset = start_offset + start_difference;
 3903            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3904                continue;
 3905            }
 3906            if self.selections.disjoint_anchor_ranges().any(|s| {
 3907                if s.start.buffer_id != selection.start.buffer_id
 3908                    || s.end.buffer_id != selection.end.buffer_id
 3909                {
 3910                    return false;
 3911                }
 3912                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3913                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3914            }) {
 3915                continue;
 3916            }
 3917            let start = buffer_snapshot.anchor_after(start_offset);
 3918            let end = buffer_snapshot.anchor_after(end_offset);
 3919            linked_edits
 3920                .entry(buffer.clone())
 3921                .or_default()
 3922                .push(start..end);
 3923        }
 3924        Some(linked_edits)
 3925    }
 3926
 3927    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3928        let text: Arc<str> = text.into();
 3929
 3930        if self.read_only(cx) {
 3931            return;
 3932        }
 3933
 3934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3935
 3936        let selections = self.selections.all_adjusted(cx);
 3937        let mut bracket_inserted = false;
 3938        let mut edits = Vec::new();
 3939        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3940        let mut new_selections = Vec::with_capacity(selections.len());
 3941        let mut new_autoclose_regions = Vec::new();
 3942        let snapshot = self.buffer.read(cx).read(cx);
 3943        let mut clear_linked_edit_ranges = false;
 3944
 3945        for (selection, autoclose_region) in
 3946            self.selections_with_autoclose_regions(selections, &snapshot)
 3947        {
 3948            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3949                // Determine if the inserted text matches the opening or closing
 3950                // bracket of any of this language's bracket pairs.
 3951                let mut bracket_pair = None;
 3952                let mut is_bracket_pair_start = false;
 3953                let mut is_bracket_pair_end = false;
 3954                if !text.is_empty() {
 3955                    let mut bracket_pair_matching_end = None;
 3956                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3957                    //  and they are removing the character that triggered IME popup.
 3958                    for (pair, enabled) in scope.brackets() {
 3959                        if !pair.close && !pair.surround {
 3960                            continue;
 3961                        }
 3962
 3963                        if enabled && pair.start.ends_with(text.as_ref()) {
 3964                            let prefix_len = pair.start.len() - text.len();
 3965                            let preceding_text_matches_prefix = prefix_len == 0
 3966                                || (selection.start.column >= (prefix_len as u32)
 3967                                    && snapshot.contains_str_at(
 3968                                        Point::new(
 3969                                            selection.start.row,
 3970                                            selection.start.column - (prefix_len as u32),
 3971                                        ),
 3972                                        &pair.start[..prefix_len],
 3973                                    ));
 3974                            if preceding_text_matches_prefix {
 3975                                bracket_pair = Some(pair.clone());
 3976                                is_bracket_pair_start = true;
 3977                                break;
 3978                            }
 3979                        }
 3980                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3981                        {
 3982                            // take first bracket pair matching end, but don't break in case a later bracket
 3983                            // pair matches start
 3984                            bracket_pair_matching_end = Some(pair.clone());
 3985                        }
 3986                    }
 3987                    if let Some(end) = bracket_pair_matching_end
 3988                        && bracket_pair.is_none()
 3989                    {
 3990                        bracket_pair = Some(end);
 3991                        is_bracket_pair_end = true;
 3992                    }
 3993                }
 3994
 3995                if let Some(bracket_pair) = bracket_pair {
 3996                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3997                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3998                    let auto_surround =
 3999                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4000                    if selection.is_empty() {
 4001                        if is_bracket_pair_start {
 4002                            // If the inserted text is a suffix of an opening bracket and the
 4003                            // selection is preceded by the rest of the opening bracket, then
 4004                            // insert the closing bracket.
 4005                            let following_text_allows_autoclose = snapshot
 4006                                .chars_at(selection.start)
 4007                                .next()
 4008                                .map_or(true, |c| scope.should_autoclose_before(c));
 4009
 4010                            let preceding_text_allows_autoclose = selection.start.column == 0
 4011                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4012                                    true,
 4013                                    |c| {
 4014                                        bracket_pair.start != bracket_pair.end
 4015                                            || !snapshot
 4016                                                .char_classifier_at(selection.start)
 4017                                                .is_word(c)
 4018                                    },
 4019                                );
 4020
 4021                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4022                                && bracket_pair.start.len() == 1
 4023                            {
 4024                                let target = bracket_pair.start.chars().next().unwrap();
 4025                                let current_line_count = snapshot
 4026                                    .reversed_chars_at(selection.start)
 4027                                    .take_while(|&c| c != '\n')
 4028                                    .filter(|&c| c == target)
 4029                                    .count();
 4030                                current_line_count % 2 == 1
 4031                            } else {
 4032                                false
 4033                            };
 4034
 4035                            if autoclose
 4036                                && bracket_pair.close
 4037                                && following_text_allows_autoclose
 4038                                && preceding_text_allows_autoclose
 4039                                && !is_closing_quote
 4040                            {
 4041                                let anchor = snapshot.anchor_before(selection.end);
 4042                                new_selections.push((selection.map(|_| anchor), text.len()));
 4043                                new_autoclose_regions.push((
 4044                                    anchor,
 4045                                    text.len(),
 4046                                    selection.id,
 4047                                    bracket_pair.clone(),
 4048                                ));
 4049                                edits.push((
 4050                                    selection.range(),
 4051                                    format!("{}{}", text, bracket_pair.end).into(),
 4052                                ));
 4053                                bracket_inserted = true;
 4054                                continue;
 4055                            }
 4056                        }
 4057
 4058                        if let Some(region) = autoclose_region {
 4059                            // If the selection is followed by an auto-inserted closing bracket,
 4060                            // then don't insert that closing bracket again; just move the selection
 4061                            // past the closing bracket.
 4062                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4063                                && text.as_ref() == region.pair.end.as_str();
 4064                            if should_skip {
 4065                                let anchor = snapshot.anchor_after(selection.end);
 4066                                new_selections
 4067                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4068                                continue;
 4069                            }
 4070                        }
 4071
 4072                        let always_treat_brackets_as_autoclosed = snapshot
 4073                            .language_settings_at(selection.start, cx)
 4074                            .always_treat_brackets_as_autoclosed;
 4075                        if always_treat_brackets_as_autoclosed
 4076                            && is_bracket_pair_end
 4077                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4078                        {
 4079                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4080                            // and the inserted text is a closing bracket and the selection is followed
 4081                            // by the closing bracket then move the selection past the closing bracket.
 4082                            let anchor = snapshot.anchor_after(selection.end);
 4083                            new_selections.push((selection.map(|_| anchor), text.len()));
 4084                            continue;
 4085                        }
 4086                    }
 4087                    // If an opening bracket is 1 character long and is typed while
 4088                    // text is selected, then surround that text with the bracket pair.
 4089                    else if auto_surround
 4090                        && bracket_pair.surround
 4091                        && is_bracket_pair_start
 4092                        && bracket_pair.start.chars().count() == 1
 4093                    {
 4094                        edits.push((selection.start..selection.start, text.clone()));
 4095                        edits.push((
 4096                            selection.end..selection.end,
 4097                            bracket_pair.end.as_str().into(),
 4098                        ));
 4099                        bracket_inserted = true;
 4100                        new_selections.push((
 4101                            Selection {
 4102                                id: selection.id,
 4103                                start: snapshot.anchor_after(selection.start),
 4104                                end: snapshot.anchor_before(selection.end),
 4105                                reversed: selection.reversed,
 4106                                goal: selection.goal,
 4107                            },
 4108                            0,
 4109                        ));
 4110                        continue;
 4111                    }
 4112                }
 4113            }
 4114
 4115            if self.auto_replace_emoji_shortcode
 4116                && selection.is_empty()
 4117                && text.as_ref().ends_with(':')
 4118            {
 4119                if let Some(possible_emoji_short_code) =
 4120                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4121                {
 4122                    if !possible_emoji_short_code.is_empty() {
 4123                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4124                            let emoji_shortcode_start = Point::new(
 4125                                selection.start.row,
 4126                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4127                            );
 4128
 4129                            // Remove shortcode from buffer
 4130                            edits.push((
 4131                                emoji_shortcode_start..selection.start,
 4132                                "".to_string().into(),
 4133                            ));
 4134                            new_selections.push((
 4135                                Selection {
 4136                                    id: selection.id,
 4137                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4138                                    end: snapshot.anchor_before(selection.start),
 4139                                    reversed: selection.reversed,
 4140                                    goal: selection.goal,
 4141                                },
 4142                                0,
 4143                            ));
 4144
 4145                            // Insert emoji
 4146                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4147                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4148                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4149
 4150                            continue;
 4151                        }
 4152                    }
 4153                }
 4154            }
 4155
 4156            // If not handling any auto-close operation, then just replace the selected
 4157            // text with the given input and move the selection to the end of the
 4158            // newly inserted text.
 4159            let anchor = snapshot.anchor_after(selection.end);
 4160            if !self.linked_edit_ranges.is_empty() {
 4161                let start_anchor = snapshot.anchor_before(selection.start);
 4162
 4163                let is_word_char = text.chars().next().map_or(true, |char| {
 4164                    let classifier = snapshot
 4165                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4166                        .ignore_punctuation(true);
 4167                    classifier.is_word(char)
 4168                });
 4169
 4170                if is_word_char {
 4171                    if let Some(ranges) = self
 4172                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4173                    {
 4174                        for (buffer, edits) in ranges {
 4175                            linked_edits
 4176                                .entry(buffer.clone())
 4177                                .or_default()
 4178                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4179                        }
 4180                    }
 4181                } else {
 4182                    clear_linked_edit_ranges = true;
 4183                }
 4184            }
 4185
 4186            new_selections.push((selection.map(|_| anchor), 0));
 4187            edits.push((selection.start..selection.end, text.clone()));
 4188        }
 4189
 4190        drop(snapshot);
 4191
 4192        self.transact(window, cx, |this, window, cx| {
 4193            if clear_linked_edit_ranges {
 4194                this.linked_edit_ranges.clear();
 4195            }
 4196            let initial_buffer_versions =
 4197                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4198
 4199            this.buffer.update(cx, |buffer, cx| {
 4200                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4201            });
 4202            for (buffer, edits) in linked_edits {
 4203                buffer.update(cx, |buffer, cx| {
 4204                    let snapshot = buffer.snapshot();
 4205                    let edits = edits
 4206                        .into_iter()
 4207                        .map(|(range, text)| {
 4208                            use text::ToPoint as TP;
 4209                            let end_point = TP::to_point(&range.end, &snapshot);
 4210                            let start_point = TP::to_point(&range.start, &snapshot);
 4211                            (start_point..end_point, text)
 4212                        })
 4213                        .sorted_by_key(|(range, _)| range.start);
 4214                    buffer.edit(edits, None, cx);
 4215                })
 4216            }
 4217            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4218            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4219            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4220            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4221                .zip(new_selection_deltas)
 4222                .map(|(selection, delta)| Selection {
 4223                    id: selection.id,
 4224                    start: selection.start + delta,
 4225                    end: selection.end + delta,
 4226                    reversed: selection.reversed,
 4227                    goal: SelectionGoal::None,
 4228                })
 4229                .collect::<Vec<_>>();
 4230
 4231            let mut i = 0;
 4232            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4233                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4234                let start = map.buffer_snapshot.anchor_before(position);
 4235                let end = map.buffer_snapshot.anchor_after(position);
 4236                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4237                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4238                        Ordering::Less => i += 1,
 4239                        Ordering::Greater => break,
 4240                        Ordering::Equal => {
 4241                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4242                                Ordering::Less => i += 1,
 4243                                Ordering::Equal => break,
 4244                                Ordering::Greater => break,
 4245                            }
 4246                        }
 4247                    }
 4248                }
 4249                this.autoclose_regions.insert(
 4250                    i,
 4251                    AutocloseRegion {
 4252                        selection_id,
 4253                        range: start..end,
 4254                        pair,
 4255                    },
 4256                );
 4257            }
 4258
 4259            let had_active_inline_completion = this.has_active_inline_completion();
 4260            this.change_selections(
 4261                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4262                window,
 4263                cx,
 4264                |s| s.select(new_selections),
 4265            );
 4266
 4267            if !bracket_inserted {
 4268                if let Some(on_type_format_task) =
 4269                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4270                {
 4271                    on_type_format_task.detach_and_log_err(cx);
 4272                }
 4273            }
 4274
 4275            let editor_settings = EditorSettings::get_global(cx);
 4276            if bracket_inserted
 4277                && (editor_settings.auto_signature_help
 4278                    || editor_settings.show_signature_help_after_edits)
 4279            {
 4280                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4281            }
 4282
 4283            let trigger_in_words =
 4284                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4285            if this.hard_wrap.is_some() {
 4286                let latest: Range<Point> = this.selections.newest(cx).range();
 4287                if latest.is_empty()
 4288                    && this
 4289                        .buffer()
 4290                        .read(cx)
 4291                        .snapshot(cx)
 4292                        .line_len(MultiBufferRow(latest.start.row))
 4293                        == latest.start.column
 4294                {
 4295                    this.rewrap_impl(
 4296                        RewrapOptions {
 4297                            override_language_settings: true,
 4298                            preserve_existing_whitespace: true,
 4299                        },
 4300                        cx,
 4301                    )
 4302                }
 4303            }
 4304            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4305            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4306            this.refresh_inline_completion(true, false, window, cx);
 4307            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4308        });
 4309    }
 4310
 4311    fn find_possible_emoji_shortcode_at_position(
 4312        snapshot: &MultiBufferSnapshot,
 4313        position: Point,
 4314    ) -> Option<String> {
 4315        let mut chars = Vec::new();
 4316        let mut found_colon = false;
 4317        for char in snapshot.reversed_chars_at(position).take(100) {
 4318            // Found a possible emoji shortcode in the middle of the buffer
 4319            if found_colon {
 4320                if char.is_whitespace() {
 4321                    chars.reverse();
 4322                    return Some(chars.iter().collect());
 4323                }
 4324                // If the previous character is not a whitespace, we are in the middle of a word
 4325                // and we only want to complete the shortcode if the word is made up of other emojis
 4326                let mut containing_word = String::new();
 4327                for ch in snapshot
 4328                    .reversed_chars_at(position)
 4329                    .skip(chars.len() + 1)
 4330                    .take(100)
 4331                {
 4332                    if ch.is_whitespace() {
 4333                        break;
 4334                    }
 4335                    containing_word.push(ch);
 4336                }
 4337                let containing_word = containing_word.chars().rev().collect::<String>();
 4338                if util::word_consists_of_emojis(containing_word.as_str()) {
 4339                    chars.reverse();
 4340                    return Some(chars.iter().collect());
 4341                }
 4342            }
 4343
 4344            if char.is_whitespace() || !char.is_ascii() {
 4345                return None;
 4346            }
 4347            if char == ':' {
 4348                found_colon = true;
 4349            } else {
 4350                chars.push(char);
 4351            }
 4352        }
 4353        // Found a possible emoji shortcode at the beginning of the buffer
 4354        chars.reverse();
 4355        Some(chars.iter().collect())
 4356    }
 4357
 4358    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4360        self.transact(window, cx, |this, window, cx| {
 4361            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4362                let selections = this.selections.all::<usize>(cx);
 4363                let multi_buffer = this.buffer.read(cx);
 4364                let buffer = multi_buffer.snapshot(cx);
 4365                selections
 4366                    .iter()
 4367                    .map(|selection| {
 4368                        let start_point = selection.start.to_point(&buffer);
 4369                        let mut existing_indent =
 4370                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4371                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4372                        let start = selection.start;
 4373                        let end = selection.end;
 4374                        let selection_is_empty = start == end;
 4375                        let language_scope = buffer.language_scope_at(start);
 4376                        let (
 4377                            comment_delimiter,
 4378                            doc_delimiter,
 4379                            insert_extra_newline,
 4380                            indent_on_newline,
 4381                            indent_on_extra_newline,
 4382                        ) = if let Some(language) = &language_scope {
 4383                            let mut insert_extra_newline =
 4384                                insert_extra_newline_brackets(&buffer, start..end, language)
 4385                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4386
 4387                            // Comment extension on newline is allowed only for cursor selections
 4388                            let comment_delimiter = maybe!({
 4389                                if !selection_is_empty {
 4390                                    return None;
 4391                                }
 4392
 4393                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4394                                    return None;
 4395                                }
 4396
 4397                                let delimiters = language.line_comment_prefixes();
 4398                                let max_len_of_delimiter =
 4399                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4400                                let (snapshot, range) =
 4401                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4402
 4403                                let num_of_whitespaces = snapshot
 4404                                    .chars_for_range(range.clone())
 4405                                    .take_while(|c| c.is_whitespace())
 4406                                    .count();
 4407                                let comment_candidate = snapshot
 4408                                    .chars_for_range(range.clone())
 4409                                    .skip(num_of_whitespaces)
 4410                                    .take(max_len_of_delimiter)
 4411                                    .collect::<String>();
 4412                                let (delimiter, trimmed_len) = delimiters
 4413                                    .iter()
 4414                                    .filter_map(|delimiter| {
 4415                                        let prefix = delimiter.trim_end();
 4416                                        if comment_candidate.starts_with(prefix) {
 4417                                            Some((delimiter, prefix.len()))
 4418                                        } else {
 4419                                            None
 4420                                        }
 4421                                    })
 4422                                    .max_by_key(|(_, len)| *len)?;
 4423
 4424                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4425                                {
 4426                                    let block_start_trimmed = block_start.trim_end();
 4427                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4428                                        let line_content = snapshot
 4429                                            .chars_for_range(range)
 4430                                            .skip(num_of_whitespaces)
 4431                                            .take(block_start_trimmed.len())
 4432                                            .collect::<String>();
 4433
 4434                                        if line_content.starts_with(block_start_trimmed) {
 4435                                            return None;
 4436                                        }
 4437                                    }
 4438                                }
 4439
 4440                                let cursor_is_placed_after_comment_marker =
 4441                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4442                                if cursor_is_placed_after_comment_marker {
 4443                                    Some(delimiter.clone())
 4444                                } else {
 4445                                    None
 4446                                }
 4447                            });
 4448
 4449                            let mut indent_on_newline = IndentSize::spaces(0);
 4450                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4451
 4452                            let doc_delimiter = maybe!({
 4453                                if !selection_is_empty {
 4454                                    return None;
 4455                                }
 4456
 4457                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4458                                    return None;
 4459                                }
 4460
 4461                                let DocumentationConfig {
 4462                                    start: start_tag,
 4463                                    end: end_tag,
 4464                                    prefix: delimiter,
 4465                                    tab_size: len,
 4466                                } = language.documentation()?;
 4467
 4468                                let is_within_block_comment = buffer
 4469                                    .language_scope_at(start_point)
 4470                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4471                                if !is_within_block_comment {
 4472                                    return None;
 4473                                }
 4474
 4475                                let (snapshot, range) =
 4476                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4477
 4478                                let num_of_whitespaces = snapshot
 4479                                    .chars_for_range(range.clone())
 4480                                    .take_while(|c| c.is_whitespace())
 4481                                    .count();
 4482
 4483                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4484                                let column = start_point.column;
 4485                                let cursor_is_after_start_tag = {
 4486                                    let start_tag_len = start_tag.len();
 4487                                    let start_tag_line = snapshot
 4488                                        .chars_for_range(range.clone())
 4489                                        .skip(num_of_whitespaces)
 4490                                        .take(start_tag_len)
 4491                                        .collect::<String>();
 4492                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4493                                        num_of_whitespaces + start_tag_len <= column as usize
 4494                                    } else {
 4495                                        false
 4496                                    }
 4497                                };
 4498
 4499                                let cursor_is_after_delimiter = {
 4500                                    let delimiter_trim = delimiter.trim_end();
 4501                                    let delimiter_line = snapshot
 4502                                        .chars_for_range(range.clone())
 4503                                        .skip(num_of_whitespaces)
 4504                                        .take(delimiter_trim.len())
 4505                                        .collect::<String>();
 4506                                    if delimiter_line.starts_with(delimiter_trim) {
 4507                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4508                                    } else {
 4509                                        false
 4510                                    }
 4511                                };
 4512
 4513                                let cursor_is_before_end_tag_if_exists = {
 4514                                    let mut char_position = 0u32;
 4515                                    let mut end_tag_offset = None;
 4516
 4517                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4518                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4519                                            let chars_before_match =
 4520                                                chunk[..byte_pos].chars().count() as u32;
 4521                                            end_tag_offset =
 4522                                                Some(char_position + chars_before_match);
 4523                                            break 'outer;
 4524                                        }
 4525                                        char_position += chunk.chars().count() as u32;
 4526                                    }
 4527
 4528                                    if let Some(end_tag_offset) = end_tag_offset {
 4529                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4530                                        if cursor_is_after_start_tag {
 4531                                            if cursor_is_before_end_tag {
 4532                                                insert_extra_newline = true;
 4533                                            }
 4534                                            let cursor_is_at_start_of_end_tag =
 4535                                                column == end_tag_offset;
 4536                                            if cursor_is_at_start_of_end_tag {
 4537                                                indent_on_extra_newline.len = (*len).into();
 4538                                            }
 4539                                        }
 4540                                        cursor_is_before_end_tag
 4541                                    } else {
 4542                                        true
 4543                                    }
 4544                                };
 4545
 4546                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4547                                    && cursor_is_before_end_tag_if_exists
 4548                                {
 4549                                    if cursor_is_after_start_tag {
 4550                                        indent_on_newline.len = (*len).into();
 4551                                    }
 4552                                    Some(delimiter.clone())
 4553                                } else {
 4554                                    None
 4555                                }
 4556                            });
 4557
 4558                            (
 4559                                comment_delimiter,
 4560                                doc_delimiter,
 4561                                insert_extra_newline,
 4562                                indent_on_newline,
 4563                                indent_on_extra_newline,
 4564                            )
 4565                        } else {
 4566                            (
 4567                                None,
 4568                                None,
 4569                                false,
 4570                                IndentSize::default(),
 4571                                IndentSize::default(),
 4572                            )
 4573                        };
 4574
 4575                        let prevent_auto_indent = doc_delimiter.is_some();
 4576                        let delimiter = comment_delimiter.or(doc_delimiter);
 4577
 4578                        let capacity_for_delimiter =
 4579                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4580                        let mut new_text = String::with_capacity(
 4581                            1 + capacity_for_delimiter
 4582                                + existing_indent.len as usize
 4583                                + indent_on_newline.len as usize
 4584                                + indent_on_extra_newline.len as usize,
 4585                        );
 4586                        new_text.push('\n');
 4587                        new_text.extend(existing_indent.chars());
 4588                        new_text.extend(indent_on_newline.chars());
 4589
 4590                        if let Some(delimiter) = &delimiter {
 4591                            new_text.push_str(delimiter);
 4592                        }
 4593
 4594                        if insert_extra_newline {
 4595                            new_text.push('\n');
 4596                            new_text.extend(existing_indent.chars());
 4597                            new_text.extend(indent_on_extra_newline.chars());
 4598                        }
 4599
 4600                        let anchor = buffer.anchor_after(end);
 4601                        let new_selection = selection.map(|_| anchor);
 4602                        (
 4603                            ((start..end, new_text), prevent_auto_indent),
 4604                            (insert_extra_newline, new_selection),
 4605                        )
 4606                    })
 4607                    .unzip()
 4608            };
 4609
 4610            let mut auto_indent_edits = Vec::new();
 4611            let mut edits = Vec::new();
 4612            for (edit, prevent_auto_indent) in edits_with_flags {
 4613                if prevent_auto_indent {
 4614                    edits.push(edit);
 4615                } else {
 4616                    auto_indent_edits.push(edit);
 4617                }
 4618            }
 4619            if !edits.is_empty() {
 4620                this.edit(edits, cx);
 4621            }
 4622            if !auto_indent_edits.is_empty() {
 4623                this.edit_with_autoindent(auto_indent_edits, cx);
 4624            }
 4625
 4626            let buffer = this.buffer.read(cx).snapshot(cx);
 4627            let new_selections = selection_info
 4628                .into_iter()
 4629                .map(|(extra_newline_inserted, new_selection)| {
 4630                    let mut cursor = new_selection.end.to_point(&buffer);
 4631                    if extra_newline_inserted {
 4632                        cursor.row -= 1;
 4633                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4634                    }
 4635                    new_selection.map(|_| cursor)
 4636                })
 4637                .collect();
 4638
 4639            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4640            this.refresh_inline_completion(true, false, window, cx);
 4641        });
 4642    }
 4643
 4644    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4645        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4646
 4647        let buffer = self.buffer.read(cx);
 4648        let snapshot = buffer.snapshot(cx);
 4649
 4650        let mut edits = Vec::new();
 4651        let mut rows = Vec::new();
 4652
 4653        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4654            let cursor = selection.head();
 4655            let row = cursor.row;
 4656
 4657            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4658
 4659            let newline = "\n".to_string();
 4660            edits.push((start_of_line..start_of_line, newline));
 4661
 4662            rows.push(row + rows_inserted as u32);
 4663        }
 4664
 4665        self.transact(window, cx, |editor, window, cx| {
 4666            editor.edit(edits, cx);
 4667
 4668            editor.change_selections(Default::default(), window, cx, |s| {
 4669                let mut index = 0;
 4670                s.move_cursors_with(|map, _, _| {
 4671                    let row = rows[index];
 4672                    index += 1;
 4673
 4674                    let point = Point::new(row, 0);
 4675                    let boundary = map.next_line_boundary(point).1;
 4676                    let clipped = map.clip_point(boundary, Bias::Left);
 4677
 4678                    (clipped, SelectionGoal::None)
 4679                });
 4680            });
 4681
 4682            let mut indent_edits = Vec::new();
 4683            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4684            for row in rows {
 4685                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4686                for (row, indent) in indents {
 4687                    if indent.len == 0 {
 4688                        continue;
 4689                    }
 4690
 4691                    let text = match indent.kind {
 4692                        IndentKind::Space => " ".repeat(indent.len as usize),
 4693                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4694                    };
 4695                    let point = Point::new(row.0, 0);
 4696                    indent_edits.push((point..point, text));
 4697                }
 4698            }
 4699            editor.edit(indent_edits, cx);
 4700        });
 4701    }
 4702
 4703    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4704        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4705
 4706        let buffer = self.buffer.read(cx);
 4707        let snapshot = buffer.snapshot(cx);
 4708
 4709        let mut edits = Vec::new();
 4710        let mut rows = Vec::new();
 4711        let mut rows_inserted = 0;
 4712
 4713        for selection in self.selections.all_adjusted(cx) {
 4714            let cursor = selection.head();
 4715            let row = cursor.row;
 4716
 4717            let point = Point::new(row + 1, 0);
 4718            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4719
 4720            let newline = "\n".to_string();
 4721            edits.push((start_of_line..start_of_line, newline));
 4722
 4723            rows_inserted += 1;
 4724            rows.push(row + rows_inserted);
 4725        }
 4726
 4727        self.transact(window, cx, |editor, window, cx| {
 4728            editor.edit(edits, cx);
 4729
 4730            editor.change_selections(Default::default(), window, cx, |s| {
 4731                let mut index = 0;
 4732                s.move_cursors_with(|map, _, _| {
 4733                    let row = rows[index];
 4734                    index += 1;
 4735
 4736                    let point = Point::new(row, 0);
 4737                    let boundary = map.next_line_boundary(point).1;
 4738                    let clipped = map.clip_point(boundary, Bias::Left);
 4739
 4740                    (clipped, SelectionGoal::None)
 4741                });
 4742            });
 4743
 4744            let mut indent_edits = Vec::new();
 4745            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4746            for row in rows {
 4747                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4748                for (row, indent) in indents {
 4749                    if indent.len == 0 {
 4750                        continue;
 4751                    }
 4752
 4753                    let text = match indent.kind {
 4754                        IndentKind::Space => " ".repeat(indent.len as usize),
 4755                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4756                    };
 4757                    let point = Point::new(row.0, 0);
 4758                    indent_edits.push((point..point, text));
 4759                }
 4760            }
 4761            editor.edit(indent_edits, cx);
 4762        });
 4763    }
 4764
 4765    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4766        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4767            original_indent_columns: Vec::new(),
 4768        });
 4769        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4770    }
 4771
 4772    fn insert_with_autoindent_mode(
 4773        &mut self,
 4774        text: &str,
 4775        autoindent_mode: Option<AutoindentMode>,
 4776        window: &mut Window,
 4777        cx: &mut Context<Self>,
 4778    ) {
 4779        if self.read_only(cx) {
 4780            return;
 4781        }
 4782
 4783        let text: Arc<str> = text.into();
 4784        self.transact(window, cx, |this, window, cx| {
 4785            let old_selections = this.selections.all_adjusted(cx);
 4786            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4787                let anchors = {
 4788                    let snapshot = buffer.read(cx);
 4789                    old_selections
 4790                        .iter()
 4791                        .map(|s| {
 4792                            let anchor = snapshot.anchor_after(s.head());
 4793                            s.map(|_| anchor)
 4794                        })
 4795                        .collect::<Vec<_>>()
 4796                };
 4797                buffer.edit(
 4798                    old_selections
 4799                        .iter()
 4800                        .map(|s| (s.start..s.end, text.clone())),
 4801                    autoindent_mode,
 4802                    cx,
 4803                );
 4804                anchors
 4805            });
 4806
 4807            this.change_selections(Default::default(), window, cx, |s| {
 4808                s.select_anchors(selection_anchors);
 4809            });
 4810
 4811            cx.notify();
 4812        });
 4813    }
 4814
 4815    fn trigger_completion_on_input(
 4816        &mut self,
 4817        text: &str,
 4818        trigger_in_words: bool,
 4819        window: &mut Window,
 4820        cx: &mut Context<Self>,
 4821    ) {
 4822        let completions_source = self
 4823            .context_menu
 4824            .borrow()
 4825            .as_ref()
 4826            .and_then(|menu| match menu {
 4827                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4828                CodeContextMenu::CodeActions(_) => None,
 4829            });
 4830
 4831        match completions_source {
 4832            Some(CompletionsMenuSource::Words) => {
 4833                self.show_word_completions(&ShowWordCompletions, window, cx)
 4834            }
 4835            Some(CompletionsMenuSource::Normal)
 4836            | Some(CompletionsMenuSource::SnippetChoices)
 4837            | None
 4838                if self.is_completion_trigger(
 4839                    text,
 4840                    trigger_in_words,
 4841                    completions_source.is_some(),
 4842                    cx,
 4843                ) =>
 4844            {
 4845                self.show_completions(
 4846                    &ShowCompletions {
 4847                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4848                    },
 4849                    window,
 4850                    cx,
 4851                )
 4852            }
 4853            _ => {
 4854                self.hide_context_menu(window, cx);
 4855            }
 4856        }
 4857    }
 4858
 4859    fn is_completion_trigger(
 4860        &self,
 4861        text: &str,
 4862        trigger_in_words: bool,
 4863        menu_is_open: bool,
 4864        cx: &mut Context<Self>,
 4865    ) -> bool {
 4866        let position = self.selections.newest_anchor().head();
 4867        let multibuffer = self.buffer.read(cx);
 4868        let Some(buffer) = position
 4869            .buffer_id
 4870            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4871        else {
 4872            return false;
 4873        };
 4874
 4875        if let Some(completion_provider) = &self.completion_provider {
 4876            completion_provider.is_completion_trigger(
 4877                &buffer,
 4878                position.text_anchor,
 4879                text,
 4880                trigger_in_words,
 4881                menu_is_open,
 4882                cx,
 4883            )
 4884        } else {
 4885            false
 4886        }
 4887    }
 4888
 4889    /// If any empty selections is touching the start of its innermost containing autoclose
 4890    /// region, expand it to select the brackets.
 4891    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4892        let selections = self.selections.all::<usize>(cx);
 4893        let buffer = self.buffer.read(cx).read(cx);
 4894        let new_selections = self
 4895            .selections_with_autoclose_regions(selections, &buffer)
 4896            .map(|(mut selection, region)| {
 4897                if !selection.is_empty() {
 4898                    return selection;
 4899                }
 4900
 4901                if let Some(region) = region {
 4902                    let mut range = region.range.to_offset(&buffer);
 4903                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4904                        range.start -= region.pair.start.len();
 4905                        if buffer.contains_str_at(range.start, &region.pair.start)
 4906                            && buffer.contains_str_at(range.end, &region.pair.end)
 4907                        {
 4908                            range.end += region.pair.end.len();
 4909                            selection.start = range.start;
 4910                            selection.end = range.end;
 4911
 4912                            return selection;
 4913                        }
 4914                    }
 4915                }
 4916
 4917                let always_treat_brackets_as_autoclosed = buffer
 4918                    .language_settings_at(selection.start, cx)
 4919                    .always_treat_brackets_as_autoclosed;
 4920
 4921                if !always_treat_brackets_as_autoclosed {
 4922                    return selection;
 4923                }
 4924
 4925                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4926                    for (pair, enabled) in scope.brackets() {
 4927                        if !enabled || !pair.close {
 4928                            continue;
 4929                        }
 4930
 4931                        if buffer.contains_str_at(selection.start, &pair.end) {
 4932                            let pair_start_len = pair.start.len();
 4933                            if buffer.contains_str_at(
 4934                                selection.start.saturating_sub(pair_start_len),
 4935                                &pair.start,
 4936                            ) {
 4937                                selection.start -= pair_start_len;
 4938                                selection.end += pair.end.len();
 4939
 4940                                return selection;
 4941                            }
 4942                        }
 4943                    }
 4944                }
 4945
 4946                selection
 4947            })
 4948            .collect();
 4949
 4950        drop(buffer);
 4951        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4952            selections.select(new_selections)
 4953        });
 4954    }
 4955
 4956    /// Iterate the given selections, and for each one, find the smallest surrounding
 4957    /// autoclose region. This uses the ordering of the selections and the autoclose
 4958    /// regions to avoid repeated comparisons.
 4959    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4960        &'a self,
 4961        selections: impl IntoIterator<Item = Selection<D>>,
 4962        buffer: &'a MultiBufferSnapshot,
 4963    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4964        let mut i = 0;
 4965        let mut regions = self.autoclose_regions.as_slice();
 4966        selections.into_iter().map(move |selection| {
 4967            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4968
 4969            let mut enclosing = None;
 4970            while let Some(pair_state) = regions.get(i) {
 4971                if pair_state.range.end.to_offset(buffer) < range.start {
 4972                    regions = &regions[i + 1..];
 4973                    i = 0;
 4974                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4975                    break;
 4976                } else {
 4977                    if pair_state.selection_id == selection.id {
 4978                        enclosing = Some(pair_state);
 4979                    }
 4980                    i += 1;
 4981                }
 4982            }
 4983
 4984            (selection, enclosing)
 4985        })
 4986    }
 4987
 4988    /// Remove any autoclose regions that no longer contain their selection.
 4989    fn invalidate_autoclose_regions(
 4990        &mut self,
 4991        mut selections: &[Selection<Anchor>],
 4992        buffer: &MultiBufferSnapshot,
 4993    ) {
 4994        self.autoclose_regions.retain(|state| {
 4995            let mut i = 0;
 4996            while let Some(selection) = selections.get(i) {
 4997                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4998                    selections = &selections[1..];
 4999                    continue;
 5000                }
 5001                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5002                    break;
 5003                }
 5004                if selection.id == state.selection_id {
 5005                    return true;
 5006                } else {
 5007                    i += 1;
 5008                }
 5009            }
 5010            false
 5011        });
 5012    }
 5013
 5014    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5015        let offset = position.to_offset(buffer);
 5016        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5017        if offset > word_range.start && kind == Some(CharKind::Word) {
 5018            Some(
 5019                buffer
 5020                    .text_for_range(word_range.start..offset)
 5021                    .collect::<String>(),
 5022            )
 5023        } else {
 5024            None
 5025        }
 5026    }
 5027
 5028    pub fn toggle_inline_values(
 5029        &mut self,
 5030        _: &ToggleInlineValues,
 5031        _: &mut Window,
 5032        cx: &mut Context<Self>,
 5033    ) {
 5034        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5035
 5036        self.refresh_inline_values(cx);
 5037    }
 5038
 5039    pub fn toggle_inlay_hints(
 5040        &mut self,
 5041        _: &ToggleInlayHints,
 5042        _: &mut Window,
 5043        cx: &mut Context<Self>,
 5044    ) {
 5045        self.refresh_inlay_hints(
 5046            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5047            cx,
 5048        );
 5049    }
 5050
 5051    pub fn inlay_hints_enabled(&self) -> bool {
 5052        self.inlay_hint_cache.enabled
 5053    }
 5054
 5055    pub fn inline_values_enabled(&self) -> bool {
 5056        self.inline_value_cache.enabled
 5057    }
 5058
 5059    #[cfg(any(test, feature = "test-support"))]
 5060    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5061        self.display_map
 5062            .read(cx)
 5063            .current_inlays()
 5064            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5065            .cloned()
 5066            .collect()
 5067    }
 5068
 5069    #[cfg(any(test, feature = "test-support"))]
 5070    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5071        self.display_map
 5072            .read(cx)
 5073            .current_inlays()
 5074            .cloned()
 5075            .collect()
 5076    }
 5077
 5078    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5079        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5080            return;
 5081        }
 5082
 5083        let reason_description = reason.description();
 5084        let ignore_debounce = matches!(
 5085            reason,
 5086            InlayHintRefreshReason::SettingsChange(_)
 5087                | InlayHintRefreshReason::Toggle(_)
 5088                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5089                | InlayHintRefreshReason::ModifiersChanged(_)
 5090        );
 5091        let (invalidate_cache, required_languages) = match reason {
 5092            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5093                match self.inlay_hint_cache.modifiers_override(enabled) {
 5094                    Some(enabled) => {
 5095                        if enabled {
 5096                            (InvalidationStrategy::RefreshRequested, None)
 5097                        } else {
 5098                            self.splice_inlays(
 5099                                &self
 5100                                    .visible_inlay_hints(cx)
 5101                                    .iter()
 5102                                    .map(|inlay| inlay.id)
 5103                                    .collect::<Vec<InlayId>>(),
 5104                                Vec::new(),
 5105                                cx,
 5106                            );
 5107                            return;
 5108                        }
 5109                    }
 5110                    None => return,
 5111                }
 5112            }
 5113            InlayHintRefreshReason::Toggle(enabled) => {
 5114                if self.inlay_hint_cache.toggle(enabled) {
 5115                    if enabled {
 5116                        (InvalidationStrategy::RefreshRequested, None)
 5117                    } else {
 5118                        self.splice_inlays(
 5119                            &self
 5120                                .visible_inlay_hints(cx)
 5121                                .iter()
 5122                                .map(|inlay| inlay.id)
 5123                                .collect::<Vec<InlayId>>(),
 5124                            Vec::new(),
 5125                            cx,
 5126                        );
 5127                        return;
 5128                    }
 5129                } else {
 5130                    return;
 5131                }
 5132            }
 5133            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5134                match self.inlay_hint_cache.update_settings(
 5135                    &self.buffer,
 5136                    new_settings,
 5137                    self.visible_inlay_hints(cx),
 5138                    cx,
 5139                ) {
 5140                    ControlFlow::Break(Some(InlaySplice {
 5141                        to_remove,
 5142                        to_insert,
 5143                    })) => {
 5144                        self.splice_inlays(&to_remove, to_insert, cx);
 5145                        return;
 5146                    }
 5147                    ControlFlow::Break(None) => return,
 5148                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5149                }
 5150            }
 5151            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5152                if let Some(InlaySplice {
 5153                    to_remove,
 5154                    to_insert,
 5155                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5156                {
 5157                    self.splice_inlays(&to_remove, to_insert, cx);
 5158                }
 5159                self.display_map.update(cx, |display_map, _| {
 5160                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5161                });
 5162                return;
 5163            }
 5164            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5165            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5166                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5167            }
 5168            InlayHintRefreshReason::RefreshRequested => {
 5169                (InvalidationStrategy::RefreshRequested, None)
 5170            }
 5171        };
 5172
 5173        if let Some(InlaySplice {
 5174            to_remove,
 5175            to_insert,
 5176        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5177            reason_description,
 5178            self.visible_excerpts(required_languages.as_ref(), cx),
 5179            invalidate_cache,
 5180            ignore_debounce,
 5181            cx,
 5182        ) {
 5183            self.splice_inlays(&to_remove, to_insert, cx);
 5184        }
 5185    }
 5186
 5187    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5188        self.display_map
 5189            .read(cx)
 5190            .current_inlays()
 5191            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5192            .cloned()
 5193            .collect()
 5194    }
 5195
 5196    pub fn visible_excerpts(
 5197        &self,
 5198        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5199        cx: &mut Context<Editor>,
 5200    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5201        let Some(project) = self.project.as_ref() else {
 5202            return HashMap::default();
 5203        };
 5204        let project = project.read(cx);
 5205        let multi_buffer = self.buffer().read(cx);
 5206        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5207        let multi_buffer_visible_start = self
 5208            .scroll_manager
 5209            .anchor()
 5210            .anchor
 5211            .to_point(&multi_buffer_snapshot);
 5212        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5213            multi_buffer_visible_start
 5214                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5215            Bias::Left,
 5216        );
 5217        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5218        multi_buffer_snapshot
 5219            .range_to_buffer_ranges(multi_buffer_visible_range)
 5220            .into_iter()
 5221            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5222            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5223                let buffer_file = project::File::from_dyn(buffer.file())?;
 5224                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5225                let worktree_entry = buffer_worktree
 5226                    .read(cx)
 5227                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5228                if worktree_entry.is_ignored {
 5229                    return None;
 5230                }
 5231
 5232                let language = buffer.language()?;
 5233                if let Some(restrict_to_languages) = restrict_to_languages {
 5234                    if !restrict_to_languages.contains(language) {
 5235                        return None;
 5236                    }
 5237                }
 5238                Some((
 5239                    excerpt_id,
 5240                    (
 5241                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5242                        buffer.version().clone(),
 5243                        excerpt_visible_range,
 5244                    ),
 5245                ))
 5246            })
 5247            .collect()
 5248    }
 5249
 5250    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5251        TextLayoutDetails {
 5252            text_system: window.text_system().clone(),
 5253            editor_style: self.style.clone().unwrap(),
 5254            rem_size: window.rem_size(),
 5255            scroll_anchor: self.scroll_manager.anchor(),
 5256            visible_rows: self.visible_line_count(),
 5257            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5258        }
 5259    }
 5260
 5261    pub fn splice_inlays(
 5262        &self,
 5263        to_remove: &[InlayId],
 5264        to_insert: Vec<Inlay>,
 5265        cx: &mut Context<Self>,
 5266    ) {
 5267        self.display_map.update(cx, |display_map, cx| {
 5268            display_map.splice_inlays(to_remove, to_insert, cx)
 5269        });
 5270        cx.notify();
 5271    }
 5272
 5273    fn trigger_on_type_formatting(
 5274        &self,
 5275        input: String,
 5276        window: &mut Window,
 5277        cx: &mut Context<Self>,
 5278    ) -> Option<Task<Result<()>>> {
 5279        if input.len() != 1 {
 5280            return None;
 5281        }
 5282
 5283        let project = self.project.as_ref()?;
 5284        let position = self.selections.newest_anchor().head();
 5285        let (buffer, buffer_position) = self
 5286            .buffer
 5287            .read(cx)
 5288            .text_anchor_for_position(position, cx)?;
 5289
 5290        let settings = language_settings::language_settings(
 5291            buffer
 5292                .read(cx)
 5293                .language_at(buffer_position)
 5294                .map(|l| l.name()),
 5295            buffer.read(cx).file(),
 5296            cx,
 5297        );
 5298        if !settings.use_on_type_format {
 5299            return None;
 5300        }
 5301
 5302        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5303        // hence we do LSP request & edit on host side only — add formats to host's history.
 5304        let push_to_lsp_host_history = true;
 5305        // If this is not the host, append its history with new edits.
 5306        let push_to_client_history = project.read(cx).is_via_collab();
 5307
 5308        let on_type_formatting = project.update(cx, |project, cx| {
 5309            project.on_type_format(
 5310                buffer.clone(),
 5311                buffer_position,
 5312                input,
 5313                push_to_lsp_host_history,
 5314                cx,
 5315            )
 5316        });
 5317        Some(cx.spawn_in(window, async move |editor, cx| {
 5318            if let Some(transaction) = on_type_formatting.await? {
 5319                if push_to_client_history {
 5320                    buffer
 5321                        .update(cx, |buffer, _| {
 5322                            buffer.push_transaction(transaction, Instant::now());
 5323                            buffer.finalize_last_transaction();
 5324                        })
 5325                        .ok();
 5326                }
 5327                editor.update(cx, |editor, cx| {
 5328                    editor.refresh_document_highlights(cx);
 5329                })?;
 5330            }
 5331            Ok(())
 5332        }))
 5333    }
 5334
 5335    pub fn show_word_completions(
 5336        &mut self,
 5337        _: &ShowWordCompletions,
 5338        window: &mut Window,
 5339        cx: &mut Context<Self>,
 5340    ) {
 5341        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5342    }
 5343
 5344    pub fn show_completions(
 5345        &mut self,
 5346        options: &ShowCompletions,
 5347        window: &mut Window,
 5348        cx: &mut Context<Self>,
 5349    ) {
 5350        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5351    }
 5352
 5353    fn open_or_update_completions_menu(
 5354        &mut self,
 5355        requested_source: Option<CompletionsMenuSource>,
 5356        trigger: Option<&str>,
 5357        window: &mut Window,
 5358        cx: &mut Context<Self>,
 5359    ) {
 5360        if self.pending_rename.is_some() {
 5361            return;
 5362        }
 5363
 5364        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5365
 5366        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5367        // inserted and selected. To handle that case, the start of the selection is used so that
 5368        // the menu starts with all choices.
 5369        let position = self
 5370            .selections
 5371            .newest_anchor()
 5372            .start
 5373            .bias_right(&multibuffer_snapshot);
 5374        if position.diff_base_anchor.is_some() {
 5375            return;
 5376        }
 5377        let (buffer, buffer_position) =
 5378            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5379                output
 5380            } else {
 5381                return;
 5382            };
 5383        let buffer_snapshot = buffer.read(cx).snapshot();
 5384
 5385        let query: Option<Arc<String>> =
 5386            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5387
 5388        drop(multibuffer_snapshot);
 5389
 5390        let provider = match requested_source {
 5391            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5392            Some(CompletionsMenuSource::Words) => None,
 5393            Some(CompletionsMenuSource::SnippetChoices) => {
 5394                log::error!("bug: SnippetChoices requested_source is not handled");
 5395                None
 5396            }
 5397        };
 5398
 5399        let sort_completions = provider
 5400            .as_ref()
 5401            .map_or(false, |provider| provider.sort_completions());
 5402
 5403        let filter_completions = provider
 5404            .as_ref()
 5405            .map_or(true, |provider| provider.filter_completions());
 5406
 5407        let trigger_kind = match trigger {
 5408            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5409                CompletionTriggerKind::TRIGGER_CHARACTER
 5410            }
 5411            _ => CompletionTriggerKind::INVOKED,
 5412        };
 5413        let completion_context = CompletionContext {
 5414            trigger_character: trigger.and_then(|trigger| {
 5415                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5416                    Some(String::from(trigger))
 5417                } else {
 5418                    None
 5419                }
 5420            }),
 5421            trigger_kind,
 5422        };
 5423
 5424        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5425        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5426        // involve trigger chars, so this is skipped in that case.
 5427        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5428        {
 5429            let menu_is_open = matches!(
 5430                self.context_menu.borrow().as_ref(),
 5431                Some(CodeContextMenu::Completions(_))
 5432            );
 5433            if menu_is_open {
 5434                self.hide_context_menu(window, cx);
 5435            }
 5436        }
 5437
 5438        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5439            if filter_completions {
 5440                menu.filter(query.clone(), provider.clone(), window, cx);
 5441            }
 5442            // When `is_incomplete` is false, no need to re-query completions when the current query
 5443            // is a suffix of the initial query.
 5444            if !menu.is_incomplete {
 5445                // If the new query is a suffix of the old query (typing more characters) and
 5446                // the previous result was complete, the existing completions can be filtered.
 5447                //
 5448                // Note that this is always true for snippet completions.
 5449                let query_matches = match (&menu.initial_query, &query) {
 5450                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5451                    (None, _) => true,
 5452                    _ => false,
 5453                };
 5454                if query_matches {
 5455                    let position_matches = if menu.initial_position == position {
 5456                        true
 5457                    } else {
 5458                        let snapshot = self.buffer.read(cx).read(cx);
 5459                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5460                    };
 5461                    if position_matches {
 5462                        return;
 5463                    }
 5464                }
 5465            }
 5466        };
 5467
 5468        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5469            buffer_snapshot.surrounding_word(buffer_position)
 5470        {
 5471            let word_to_exclude = buffer_snapshot
 5472                .text_for_range(word_range.clone())
 5473                .collect::<String>();
 5474            (
 5475                buffer_snapshot.anchor_before(word_range.start)
 5476                    ..buffer_snapshot.anchor_after(buffer_position),
 5477                Some(word_to_exclude),
 5478            )
 5479        } else {
 5480            (buffer_position..buffer_position, None)
 5481        };
 5482
 5483        let language = buffer_snapshot
 5484            .language_at(buffer_position)
 5485            .map(|language| language.name());
 5486
 5487        let completion_settings =
 5488            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5489
 5490        let show_completion_documentation = buffer_snapshot
 5491            .settings_at(buffer_position, cx)
 5492            .show_completion_documentation;
 5493
 5494        // The document can be large, so stay in reasonable bounds when searching for words,
 5495        // otherwise completion pop-up might be slow to appear.
 5496        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5497        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5498        let min_word_search = buffer_snapshot.clip_point(
 5499            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5500            Bias::Left,
 5501        );
 5502        let max_word_search = buffer_snapshot.clip_point(
 5503            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5504            Bias::Right,
 5505        );
 5506        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5507            ..buffer_snapshot.point_to_offset(max_word_search);
 5508
 5509        let skip_digits = query
 5510            .as_ref()
 5511            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5512
 5513        let (mut words, provider_responses) = match &provider {
 5514            Some(provider) => {
 5515                let provider_responses = provider.completions(
 5516                    position.excerpt_id,
 5517                    &buffer,
 5518                    buffer_position,
 5519                    completion_context,
 5520                    window,
 5521                    cx,
 5522                );
 5523
 5524                let words = match completion_settings.words {
 5525                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5526                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5527                        .background_spawn(async move {
 5528                            buffer_snapshot.words_in_range(WordsQuery {
 5529                                fuzzy_contents: None,
 5530                                range: word_search_range,
 5531                                skip_digits,
 5532                            })
 5533                        }),
 5534                };
 5535
 5536                (words, provider_responses)
 5537            }
 5538            None => (
 5539                cx.background_spawn(async move {
 5540                    buffer_snapshot.words_in_range(WordsQuery {
 5541                        fuzzy_contents: None,
 5542                        range: word_search_range,
 5543                        skip_digits,
 5544                    })
 5545                }),
 5546                Task::ready(Ok(Vec::new())),
 5547            ),
 5548        };
 5549
 5550        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5551
 5552        let id = post_inc(&mut self.next_completion_id);
 5553        let task = cx.spawn_in(window, async move |editor, cx| {
 5554            let Ok(()) = editor.update(cx, |this, _| {
 5555                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5556            }) else {
 5557                return;
 5558            };
 5559
 5560            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5561            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5562            let mut completions = Vec::new();
 5563            let mut is_incomplete = false;
 5564            if let Some(provider_responses) = provider_responses.await.log_err() {
 5565                if !provider_responses.is_empty() {
 5566                    for response in provider_responses {
 5567                        completions.extend(response.completions);
 5568                        is_incomplete = is_incomplete || response.is_incomplete;
 5569                    }
 5570                    if completion_settings.words == WordsCompletionMode::Fallback {
 5571                        words = Task::ready(BTreeMap::default());
 5572                    }
 5573                }
 5574            }
 5575
 5576            let mut words = words.await;
 5577            if let Some(word_to_exclude) = &word_to_exclude {
 5578                words.remove(word_to_exclude);
 5579            }
 5580            for lsp_completion in &completions {
 5581                words.remove(&lsp_completion.new_text);
 5582            }
 5583            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5584                replace_range: word_replace_range.clone(),
 5585                new_text: word.clone(),
 5586                label: CodeLabel::plain(word, None),
 5587                icon_path: None,
 5588                documentation: None,
 5589                source: CompletionSource::BufferWord {
 5590                    word_range,
 5591                    resolved: false,
 5592                },
 5593                insert_text_mode: Some(InsertTextMode::AS_IS),
 5594                confirm: None,
 5595            }));
 5596
 5597            let menu = if completions.is_empty() {
 5598                None
 5599            } else {
 5600                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5601                    let languages = editor
 5602                        .workspace
 5603                        .as_ref()
 5604                        .and_then(|(workspace, _)| workspace.upgrade())
 5605                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5606                    let menu = CompletionsMenu::new(
 5607                        id,
 5608                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5609                        sort_completions,
 5610                        show_completion_documentation,
 5611                        position,
 5612                        query.clone(),
 5613                        is_incomplete,
 5614                        buffer.clone(),
 5615                        completions.into(),
 5616                        snippet_sort_order,
 5617                        languages,
 5618                        language,
 5619                        cx,
 5620                    );
 5621
 5622                    let query = if filter_completions { query } else { None };
 5623                    let matches_task = if let Some(query) = query {
 5624                        menu.do_async_filtering(query, cx)
 5625                    } else {
 5626                        Task::ready(menu.unfiltered_matches())
 5627                    };
 5628                    (menu, matches_task)
 5629                }) else {
 5630                    return;
 5631                };
 5632
 5633                let matches = matches_task.await;
 5634
 5635                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5636                    // Newer menu already set, so exit.
 5637                    match editor.context_menu.borrow().as_ref() {
 5638                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5639                            if prev_menu.id > id {
 5640                                return;
 5641                            }
 5642                        }
 5643                        _ => {}
 5644                    };
 5645
 5646                    // Only valid to take prev_menu because it the new menu is immediately set
 5647                    // below, or the menu is hidden.
 5648                    match editor.context_menu.borrow_mut().take() {
 5649                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5650                            let position_matches =
 5651                                if prev_menu.initial_position == menu.initial_position {
 5652                                    true
 5653                                } else {
 5654                                    let snapshot = editor.buffer.read(cx).read(cx);
 5655                                    prev_menu.initial_position.to_offset(&snapshot)
 5656                                        == menu.initial_position.to_offset(&snapshot)
 5657                                };
 5658                            if position_matches {
 5659                                // Preserve markdown cache before `set_filter_results` because it will
 5660                                // try to populate the documentation cache.
 5661                                menu.preserve_markdown_cache(prev_menu);
 5662                            }
 5663                        }
 5664                        _ => {}
 5665                    };
 5666
 5667                    menu.set_filter_results(matches, provider, window, cx);
 5668                }) else {
 5669                    return;
 5670                };
 5671
 5672                menu.visible().then_some(menu)
 5673            };
 5674
 5675            editor
 5676                .update_in(cx, |editor, window, cx| {
 5677                    if editor.focus_handle.is_focused(window) {
 5678                        if let Some(menu) = menu {
 5679                            *editor.context_menu.borrow_mut() =
 5680                                Some(CodeContextMenu::Completions(menu));
 5681
 5682                            crate::hover_popover::hide_hover(editor, cx);
 5683                            if editor.show_edit_predictions_in_menu() {
 5684                                editor.update_visible_inline_completion(window, cx);
 5685                            } else {
 5686                                editor.discard_inline_completion(false, cx);
 5687                            }
 5688
 5689                            cx.notify();
 5690                            return;
 5691                        }
 5692                    }
 5693
 5694                    if editor.completion_tasks.len() <= 1 {
 5695                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5696                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5697                        // If it was already hidden and we don't show inline completions in the menu, we should
 5698                        // also show the inline-completion when available.
 5699                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5700                            editor.update_visible_inline_completion(window, cx);
 5701                        }
 5702                    }
 5703                })
 5704                .ok();
 5705        });
 5706
 5707        self.completion_tasks.push((id, task));
 5708    }
 5709
 5710    #[cfg(feature = "test-support")]
 5711    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5712        let menu = self.context_menu.borrow();
 5713        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5714            let completions = menu.completions.borrow();
 5715            Some(completions.to_vec())
 5716        } else {
 5717            None
 5718        }
 5719    }
 5720
 5721    pub fn with_completions_menu_matching_id<R>(
 5722        &self,
 5723        id: CompletionId,
 5724        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5725    ) -> R {
 5726        let mut context_menu = self.context_menu.borrow_mut();
 5727        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5728            return f(None);
 5729        };
 5730        if completions_menu.id != id {
 5731            return f(None);
 5732        }
 5733        f(Some(completions_menu))
 5734    }
 5735
 5736    pub fn confirm_completion(
 5737        &mut self,
 5738        action: &ConfirmCompletion,
 5739        window: &mut Window,
 5740        cx: &mut Context<Self>,
 5741    ) -> Option<Task<Result<()>>> {
 5742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5743        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5744    }
 5745
 5746    pub fn confirm_completion_insert(
 5747        &mut self,
 5748        _: &ConfirmCompletionInsert,
 5749        window: &mut Window,
 5750        cx: &mut Context<Self>,
 5751    ) -> Option<Task<Result<()>>> {
 5752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5753        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5754    }
 5755
 5756    pub fn confirm_completion_replace(
 5757        &mut self,
 5758        _: &ConfirmCompletionReplace,
 5759        window: &mut Window,
 5760        cx: &mut Context<Self>,
 5761    ) -> Option<Task<Result<()>>> {
 5762        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5763        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5764    }
 5765
 5766    pub fn compose_completion(
 5767        &mut self,
 5768        action: &ComposeCompletion,
 5769        window: &mut Window,
 5770        cx: &mut Context<Self>,
 5771    ) -> Option<Task<Result<()>>> {
 5772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5773        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5774    }
 5775
 5776    fn do_completion(
 5777        &mut self,
 5778        item_ix: Option<usize>,
 5779        intent: CompletionIntent,
 5780        window: &mut Window,
 5781        cx: &mut Context<Editor>,
 5782    ) -> Option<Task<Result<()>>> {
 5783        use language::ToOffset as _;
 5784
 5785        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5786        else {
 5787            return None;
 5788        };
 5789
 5790        let candidate_id = {
 5791            let entries = completions_menu.entries.borrow();
 5792            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5793            if self.show_edit_predictions_in_menu() {
 5794                self.discard_inline_completion(true, cx);
 5795            }
 5796            mat.candidate_id
 5797        };
 5798
 5799        let completion = completions_menu
 5800            .completions
 5801            .borrow()
 5802            .get(candidate_id)?
 5803            .clone();
 5804        cx.stop_propagation();
 5805
 5806        let buffer_handle = completions_menu.buffer.clone();
 5807
 5808        let CompletionEdit {
 5809            new_text,
 5810            snippet,
 5811            replace_range,
 5812        } = process_completion_for_edit(
 5813            &completion,
 5814            intent,
 5815            &buffer_handle,
 5816            &completions_menu.initial_position.text_anchor,
 5817            cx,
 5818        );
 5819
 5820        let buffer = buffer_handle.read(cx);
 5821        let snapshot = self.buffer.read(cx).snapshot(cx);
 5822        let newest_anchor = self.selections.newest_anchor();
 5823        let replace_range_multibuffer = {
 5824            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5825            let multibuffer_anchor = snapshot
 5826                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5827                .unwrap()
 5828                ..snapshot
 5829                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5830                    .unwrap();
 5831            multibuffer_anchor.start.to_offset(&snapshot)
 5832                ..multibuffer_anchor.end.to_offset(&snapshot)
 5833        };
 5834        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5835            return None;
 5836        }
 5837
 5838        let old_text = buffer
 5839            .text_for_range(replace_range.clone())
 5840            .collect::<String>();
 5841        let lookbehind = newest_anchor
 5842            .start
 5843            .text_anchor
 5844            .to_offset(buffer)
 5845            .saturating_sub(replace_range.start);
 5846        let lookahead = replace_range
 5847            .end
 5848            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5849        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5850        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5851
 5852        let selections = self.selections.all::<usize>(cx);
 5853        let mut ranges = Vec::new();
 5854        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5855
 5856        for selection in &selections {
 5857            let range = if selection.id == newest_anchor.id {
 5858                replace_range_multibuffer.clone()
 5859            } else {
 5860                let mut range = selection.range();
 5861
 5862                // if prefix is present, don't duplicate it
 5863                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5864                    range.start = range.start.saturating_sub(lookbehind);
 5865
 5866                    // if suffix is also present, mimic the newest cursor and replace it
 5867                    if selection.id != newest_anchor.id
 5868                        && snapshot.contains_str_at(range.end, suffix)
 5869                    {
 5870                        range.end += lookahead;
 5871                    }
 5872                }
 5873                range
 5874            };
 5875
 5876            ranges.push(range.clone());
 5877
 5878            if !self.linked_edit_ranges.is_empty() {
 5879                let start_anchor = snapshot.anchor_before(range.start);
 5880                let end_anchor = snapshot.anchor_after(range.end);
 5881                if let Some(ranges) = self
 5882                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5883                {
 5884                    for (buffer, edits) in ranges {
 5885                        linked_edits
 5886                            .entry(buffer.clone())
 5887                            .or_default()
 5888                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5889                    }
 5890                }
 5891            }
 5892        }
 5893
 5894        let common_prefix_len = old_text
 5895            .chars()
 5896            .zip(new_text.chars())
 5897            .take_while(|(a, b)| a == b)
 5898            .map(|(a, _)| a.len_utf8())
 5899            .sum::<usize>();
 5900
 5901        cx.emit(EditorEvent::InputHandled {
 5902            utf16_range_to_replace: None,
 5903            text: new_text[common_prefix_len..].into(),
 5904        });
 5905
 5906        self.transact(window, cx, |this, window, cx| {
 5907            if let Some(mut snippet) = snippet {
 5908                snippet.text = new_text.to_string();
 5909                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5910            } else {
 5911                this.buffer.update(cx, |buffer, cx| {
 5912                    let auto_indent = match completion.insert_text_mode {
 5913                        Some(InsertTextMode::AS_IS) => None,
 5914                        _ => this.autoindent_mode.clone(),
 5915                    };
 5916                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5917                    buffer.edit(edits, auto_indent, cx);
 5918                });
 5919            }
 5920            for (buffer, edits) in linked_edits {
 5921                buffer.update(cx, |buffer, cx| {
 5922                    let snapshot = buffer.snapshot();
 5923                    let edits = edits
 5924                        .into_iter()
 5925                        .map(|(range, text)| {
 5926                            use text::ToPoint as TP;
 5927                            let end_point = TP::to_point(&range.end, &snapshot);
 5928                            let start_point = TP::to_point(&range.start, &snapshot);
 5929                            (start_point..end_point, text)
 5930                        })
 5931                        .sorted_by_key(|(range, _)| range.start);
 5932                    buffer.edit(edits, None, cx);
 5933                })
 5934            }
 5935
 5936            this.refresh_inline_completion(true, false, window, cx);
 5937        });
 5938
 5939        let show_new_completions_on_confirm = completion
 5940            .confirm
 5941            .as_ref()
 5942            .map_or(false, |confirm| confirm(intent, window, cx));
 5943        if show_new_completions_on_confirm {
 5944            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5945        }
 5946
 5947        let provider = self.completion_provider.as_ref()?;
 5948        drop(completion);
 5949        let apply_edits = provider.apply_additional_edits_for_completion(
 5950            buffer_handle,
 5951            completions_menu.completions.clone(),
 5952            candidate_id,
 5953            true,
 5954            cx,
 5955        );
 5956
 5957        let editor_settings = EditorSettings::get_global(cx);
 5958        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5959            // After the code completion is finished, users often want to know what signatures are needed.
 5960            // so we should automatically call signature_help
 5961            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5962        }
 5963
 5964        Some(cx.foreground_executor().spawn(async move {
 5965            apply_edits.await?;
 5966            Ok(())
 5967        }))
 5968    }
 5969
 5970    pub fn toggle_code_actions(
 5971        &mut self,
 5972        action: &ToggleCodeActions,
 5973        window: &mut Window,
 5974        cx: &mut Context<Self>,
 5975    ) {
 5976        let quick_launch = action.quick_launch;
 5977        let mut context_menu = self.context_menu.borrow_mut();
 5978        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5979            if code_actions.deployed_from == action.deployed_from {
 5980                // Toggle if we're selecting the same one
 5981                *context_menu = None;
 5982                cx.notify();
 5983                return;
 5984            } else {
 5985                // Otherwise, clear it and start a new one
 5986                *context_menu = None;
 5987                cx.notify();
 5988            }
 5989        }
 5990        drop(context_menu);
 5991        let snapshot = self.snapshot(window, cx);
 5992        let deployed_from = action.deployed_from.clone();
 5993        let action = action.clone();
 5994        self.completion_tasks.clear();
 5995        self.discard_inline_completion(false, cx);
 5996
 5997        let multibuffer_point = match &action.deployed_from {
 5998            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5999                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6000            }
 6001            _ => self.selections.newest::<Point>(cx).head(),
 6002        };
 6003        let Some((buffer, buffer_row)) = snapshot
 6004            .buffer_snapshot
 6005            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6006            .and_then(|(buffer_snapshot, range)| {
 6007                self.buffer()
 6008                    .read(cx)
 6009                    .buffer(buffer_snapshot.remote_id())
 6010                    .map(|buffer| (buffer, range.start.row))
 6011            })
 6012        else {
 6013            return;
 6014        };
 6015        let buffer_id = buffer.read(cx).remote_id();
 6016        let tasks = self
 6017            .tasks
 6018            .get(&(buffer_id, buffer_row))
 6019            .map(|t| Arc::new(t.to_owned()));
 6020
 6021        if !self.focus_handle.is_focused(window) {
 6022            return;
 6023        }
 6024        let project = self.project.clone();
 6025
 6026        let code_actions_task = match deployed_from {
 6027            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6028            _ => self.code_actions(buffer_row, window, cx),
 6029        };
 6030
 6031        let runnable_task = match deployed_from {
 6032            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6033            _ => {
 6034                let mut task_context_task = Task::ready(None);
 6035                if let Some(tasks) = &tasks {
 6036                    if let Some(project) = project {
 6037                        task_context_task =
 6038                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6039                    }
 6040                }
 6041
 6042                cx.spawn_in(window, {
 6043                    let buffer = buffer.clone();
 6044                    async move |editor, cx| {
 6045                        let task_context = task_context_task.await;
 6046
 6047                        let resolved_tasks =
 6048                            tasks
 6049                                .zip(task_context.clone())
 6050                                .map(|(tasks, task_context)| ResolvedTasks {
 6051                                    templates: tasks.resolve(&task_context).collect(),
 6052                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6053                                        multibuffer_point.row,
 6054                                        tasks.column,
 6055                                    )),
 6056                                });
 6057                        let debug_scenarios = editor
 6058                            .update(cx, |editor, cx| {
 6059                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6060                            })?
 6061                            .await;
 6062                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6063                    }
 6064                })
 6065            }
 6066        };
 6067
 6068        cx.spawn_in(window, async move |editor, cx| {
 6069            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6070            let code_actions = code_actions_task.await;
 6071            let spawn_straight_away = quick_launch
 6072                && resolved_tasks
 6073                    .as_ref()
 6074                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6075                && code_actions
 6076                    .as_ref()
 6077                    .map_or(true, |actions| actions.is_empty())
 6078                && debug_scenarios.is_empty();
 6079
 6080            editor.update_in(cx, |editor, window, cx| {
 6081                crate::hover_popover::hide_hover(editor, cx);
 6082                let actions = CodeActionContents::new(
 6083                    resolved_tasks,
 6084                    code_actions,
 6085                    debug_scenarios,
 6086                    task_context.unwrap_or_default(),
 6087                );
 6088
 6089                // Don't show the menu if there are no actions available
 6090                if actions.is_empty() {
 6091                    cx.notify();
 6092                    return Task::ready(Ok(()));
 6093                }
 6094
 6095                *editor.context_menu.borrow_mut() =
 6096                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6097                        buffer,
 6098                        actions,
 6099                        selected_item: Default::default(),
 6100                        scroll_handle: UniformListScrollHandle::default(),
 6101                        deployed_from,
 6102                    }));
 6103                cx.notify();
 6104                if spawn_straight_away {
 6105                    if let Some(task) = editor.confirm_code_action(
 6106                        &ConfirmCodeAction { item_ix: Some(0) },
 6107                        window,
 6108                        cx,
 6109                    ) {
 6110                        return task;
 6111                    }
 6112                }
 6113
 6114                Task::ready(Ok(()))
 6115            })
 6116        })
 6117        .detach_and_log_err(cx);
 6118    }
 6119
 6120    fn debug_scenarios(
 6121        &mut self,
 6122        resolved_tasks: &Option<ResolvedTasks>,
 6123        buffer: &Entity<Buffer>,
 6124        cx: &mut App,
 6125    ) -> Task<Vec<task::DebugScenario>> {
 6126        maybe!({
 6127            let project = self.project.as_ref()?;
 6128            let dap_store = project.read(cx).dap_store();
 6129            let mut scenarios = vec![];
 6130            let resolved_tasks = resolved_tasks.as_ref()?;
 6131            let buffer = buffer.read(cx);
 6132            let language = buffer.language()?;
 6133            let file = buffer.file();
 6134            let debug_adapter = language_settings(language.name().into(), file, cx)
 6135                .debuggers
 6136                .first()
 6137                .map(SharedString::from)
 6138                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6139
 6140            dap_store.update(cx, |dap_store, cx| {
 6141                for (_, task) in &resolved_tasks.templates {
 6142                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6143                        task.original_task().clone(),
 6144                        debug_adapter.clone().into(),
 6145                        task.display_label().to_owned().into(),
 6146                        cx,
 6147                    );
 6148                    scenarios.push(maybe_scenario);
 6149                }
 6150            });
 6151            Some(cx.background_spawn(async move {
 6152                let scenarios = futures::future::join_all(scenarios)
 6153                    .await
 6154                    .into_iter()
 6155                    .flatten()
 6156                    .collect::<Vec<_>>();
 6157                scenarios
 6158            }))
 6159        })
 6160        .unwrap_or_else(|| Task::ready(vec![]))
 6161    }
 6162
 6163    fn code_actions(
 6164        &mut self,
 6165        buffer_row: u32,
 6166        window: &mut Window,
 6167        cx: &mut Context<Self>,
 6168    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6169        let mut task = self.code_actions_task.take();
 6170        cx.spawn_in(window, async move |editor, cx| {
 6171            while let Some(prev_task) = task {
 6172                prev_task.await.log_err();
 6173                task = editor
 6174                    .update(cx, |this, _| this.code_actions_task.take())
 6175                    .ok()?;
 6176            }
 6177
 6178            editor
 6179                .update(cx, |editor, cx| {
 6180                    editor
 6181                        .available_code_actions
 6182                        .clone()
 6183                        .and_then(|(location, code_actions)| {
 6184                            let snapshot = location.buffer.read(cx).snapshot();
 6185                            let point_range = location.range.to_point(&snapshot);
 6186                            let point_range = point_range.start.row..=point_range.end.row;
 6187                            if point_range.contains(&buffer_row) {
 6188                                Some(code_actions)
 6189                            } else {
 6190                                None
 6191                            }
 6192                        })
 6193                })
 6194                .ok()
 6195                .flatten()
 6196        })
 6197    }
 6198
 6199    pub fn confirm_code_action(
 6200        &mut self,
 6201        action: &ConfirmCodeAction,
 6202        window: &mut Window,
 6203        cx: &mut Context<Self>,
 6204    ) -> Option<Task<Result<()>>> {
 6205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6206
 6207        let actions_menu =
 6208            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6209                menu
 6210            } else {
 6211                return None;
 6212            };
 6213
 6214        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6215        let action = actions_menu.actions.get(action_ix)?;
 6216        let title = action.label();
 6217        let buffer = actions_menu.buffer;
 6218        let workspace = self.workspace()?;
 6219
 6220        match action {
 6221            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6222                workspace.update(cx, |workspace, cx| {
 6223                    workspace.schedule_resolved_task(
 6224                        task_source_kind,
 6225                        resolved_task,
 6226                        false,
 6227                        window,
 6228                        cx,
 6229                    );
 6230
 6231                    Some(Task::ready(Ok(())))
 6232                })
 6233            }
 6234            CodeActionsItem::CodeAction {
 6235                excerpt_id,
 6236                action,
 6237                provider,
 6238            } => {
 6239                let apply_code_action =
 6240                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6241                let workspace = workspace.downgrade();
 6242                Some(cx.spawn_in(window, async move |editor, cx| {
 6243                    let project_transaction = apply_code_action.await?;
 6244                    Self::open_project_transaction(
 6245                        &editor,
 6246                        workspace,
 6247                        project_transaction,
 6248                        title,
 6249                        cx,
 6250                    )
 6251                    .await
 6252                }))
 6253            }
 6254            CodeActionsItem::DebugScenario(scenario) => {
 6255                let context = actions_menu.actions.context.clone();
 6256
 6257                workspace.update(cx, |workspace, cx| {
 6258                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6259                    workspace.start_debug_session(
 6260                        scenario,
 6261                        context,
 6262                        Some(buffer),
 6263                        None,
 6264                        window,
 6265                        cx,
 6266                    );
 6267                });
 6268                Some(Task::ready(Ok(())))
 6269            }
 6270        }
 6271    }
 6272
 6273    pub async fn open_project_transaction(
 6274        this: &WeakEntity<Editor>,
 6275        workspace: WeakEntity<Workspace>,
 6276        transaction: ProjectTransaction,
 6277        title: String,
 6278        cx: &mut AsyncWindowContext,
 6279    ) -> Result<()> {
 6280        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6281        cx.update(|_, cx| {
 6282            entries.sort_unstable_by_key(|(buffer, _)| {
 6283                buffer.read(cx).file().map(|f| f.path().clone())
 6284            });
 6285        })?;
 6286
 6287        // If the project transaction's edits are all contained within this editor, then
 6288        // avoid opening a new editor to display them.
 6289
 6290        if let Some((buffer, transaction)) = entries.first() {
 6291            if entries.len() == 1 {
 6292                let excerpt = this.update(cx, |editor, cx| {
 6293                    editor
 6294                        .buffer()
 6295                        .read(cx)
 6296                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6297                })?;
 6298                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6299                    if excerpted_buffer == *buffer {
 6300                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6301                            let excerpt_range = excerpt_range.to_offset(buffer);
 6302                            buffer
 6303                                .edited_ranges_for_transaction::<usize>(transaction)
 6304                                .all(|range| {
 6305                                    excerpt_range.start <= range.start
 6306                                        && excerpt_range.end >= range.end
 6307                                })
 6308                        })?;
 6309
 6310                        if all_edits_within_excerpt {
 6311                            return Ok(());
 6312                        }
 6313                    }
 6314                }
 6315            }
 6316        } else {
 6317            return Ok(());
 6318        }
 6319
 6320        let mut ranges_to_highlight = Vec::new();
 6321        let excerpt_buffer = cx.new(|cx| {
 6322            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6323            for (buffer_handle, transaction) in &entries {
 6324                let edited_ranges = buffer_handle
 6325                    .read(cx)
 6326                    .edited_ranges_for_transaction::<Point>(transaction)
 6327                    .collect::<Vec<_>>();
 6328                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6329                    PathKey::for_buffer(buffer_handle, cx),
 6330                    buffer_handle.clone(),
 6331                    edited_ranges,
 6332                    DEFAULT_MULTIBUFFER_CONTEXT,
 6333                    cx,
 6334                );
 6335
 6336                ranges_to_highlight.extend(ranges);
 6337            }
 6338            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6339            multibuffer
 6340        })?;
 6341
 6342        workspace.update_in(cx, |workspace, window, cx| {
 6343            let project = workspace.project().clone();
 6344            let editor =
 6345                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6346            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6347            editor.update(cx, |editor, cx| {
 6348                editor.highlight_background::<Self>(
 6349                    &ranges_to_highlight,
 6350                    |theme| theme.colors().editor_highlighted_line_background,
 6351                    cx,
 6352                );
 6353            });
 6354        })?;
 6355
 6356        Ok(())
 6357    }
 6358
 6359    pub fn clear_code_action_providers(&mut self) {
 6360        self.code_action_providers.clear();
 6361        self.available_code_actions.take();
 6362    }
 6363
 6364    pub fn add_code_action_provider(
 6365        &mut self,
 6366        provider: Rc<dyn CodeActionProvider>,
 6367        window: &mut Window,
 6368        cx: &mut Context<Self>,
 6369    ) {
 6370        if self
 6371            .code_action_providers
 6372            .iter()
 6373            .any(|existing_provider| existing_provider.id() == provider.id())
 6374        {
 6375            return;
 6376        }
 6377
 6378        self.code_action_providers.push(provider);
 6379        self.refresh_code_actions(window, cx);
 6380    }
 6381
 6382    pub fn remove_code_action_provider(
 6383        &mut self,
 6384        id: Arc<str>,
 6385        window: &mut Window,
 6386        cx: &mut Context<Self>,
 6387    ) {
 6388        self.code_action_providers
 6389            .retain(|provider| provider.id() != id);
 6390        self.refresh_code_actions(window, cx);
 6391    }
 6392
 6393    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6394        !self.code_action_providers.is_empty()
 6395            && EditorSettings::get_global(cx).toolbar.code_actions
 6396    }
 6397
 6398    pub fn has_available_code_actions(&self) -> bool {
 6399        self.available_code_actions
 6400            .as_ref()
 6401            .is_some_and(|(_, actions)| !actions.is_empty())
 6402    }
 6403
 6404    fn render_inline_code_actions(
 6405        &self,
 6406        icon_size: ui::IconSize,
 6407        display_row: DisplayRow,
 6408        is_active: bool,
 6409        cx: &mut Context<Self>,
 6410    ) -> AnyElement {
 6411        let show_tooltip = !self.context_menu_visible();
 6412        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6413            .icon_size(icon_size)
 6414            .shape(ui::IconButtonShape::Square)
 6415            .style(ButtonStyle::Transparent)
 6416            .icon_color(ui::Color::Hidden)
 6417            .toggle_state(is_active)
 6418            .when(show_tooltip, |this| {
 6419                this.tooltip({
 6420                    let focus_handle = self.focus_handle.clone();
 6421                    move |window, cx| {
 6422                        Tooltip::for_action_in(
 6423                            "Toggle Code Actions",
 6424                            &ToggleCodeActions {
 6425                                deployed_from: None,
 6426                                quick_launch: false,
 6427                            },
 6428                            &focus_handle,
 6429                            window,
 6430                            cx,
 6431                        )
 6432                    }
 6433                })
 6434            })
 6435            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6436                window.focus(&editor.focus_handle(cx));
 6437                editor.toggle_code_actions(
 6438                    &crate::actions::ToggleCodeActions {
 6439                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6440                            display_row,
 6441                        )),
 6442                        quick_launch: false,
 6443                    },
 6444                    window,
 6445                    cx,
 6446                );
 6447            }))
 6448            .into_any_element()
 6449    }
 6450
 6451    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6452        &self.context_menu
 6453    }
 6454
 6455    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6456        let newest_selection = self.selections.newest_anchor().clone();
 6457        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6458        let buffer = self.buffer.read(cx);
 6459        if newest_selection.head().diff_base_anchor.is_some() {
 6460            return None;
 6461        }
 6462        let (start_buffer, start) =
 6463            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6464        let (end_buffer, end) =
 6465            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6466        if start_buffer != end_buffer {
 6467            return None;
 6468        }
 6469
 6470        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6471            cx.background_executor()
 6472                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6473                .await;
 6474
 6475            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6476                let providers = this.code_action_providers.clone();
 6477                let tasks = this
 6478                    .code_action_providers
 6479                    .iter()
 6480                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6481                    .collect::<Vec<_>>();
 6482                (providers, tasks)
 6483            })?;
 6484
 6485            let mut actions = Vec::new();
 6486            for (provider, provider_actions) in
 6487                providers.into_iter().zip(future::join_all(tasks).await)
 6488            {
 6489                if let Some(provider_actions) = provider_actions.log_err() {
 6490                    actions.extend(provider_actions.into_iter().map(|action| {
 6491                        AvailableCodeAction {
 6492                            excerpt_id: newest_selection.start.excerpt_id,
 6493                            action,
 6494                            provider: provider.clone(),
 6495                        }
 6496                    }));
 6497                }
 6498            }
 6499
 6500            this.update(cx, |this, cx| {
 6501                this.available_code_actions = if actions.is_empty() {
 6502                    None
 6503                } else {
 6504                    Some((
 6505                        Location {
 6506                            buffer: start_buffer,
 6507                            range: start..end,
 6508                        },
 6509                        actions.into(),
 6510                    ))
 6511                };
 6512                cx.notify();
 6513            })
 6514        }));
 6515        None
 6516    }
 6517
 6518    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6519        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6520            self.show_git_blame_inline = false;
 6521
 6522            self.show_git_blame_inline_delay_task =
 6523                Some(cx.spawn_in(window, async move |this, cx| {
 6524                    cx.background_executor().timer(delay).await;
 6525
 6526                    this.update(cx, |this, cx| {
 6527                        this.show_git_blame_inline = true;
 6528                        cx.notify();
 6529                    })
 6530                    .log_err();
 6531                }));
 6532        }
 6533    }
 6534
 6535    fn show_blame_popover(
 6536        &mut self,
 6537        blame_entry: &BlameEntry,
 6538        position: gpui::Point<Pixels>,
 6539        cx: &mut Context<Self>,
 6540    ) {
 6541        if let Some(state) = &mut self.inline_blame_popover {
 6542            state.hide_task.take();
 6543        } else {
 6544            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6545            let blame_entry = blame_entry.clone();
 6546            let show_task = cx.spawn(async move |editor, cx| {
 6547                cx.background_executor()
 6548                    .timer(std::time::Duration::from_millis(delay))
 6549                    .await;
 6550                editor
 6551                    .update(cx, |editor, cx| {
 6552                        editor.inline_blame_popover_show_task.take();
 6553                        let Some(blame) = editor.blame.as_ref() else {
 6554                            return;
 6555                        };
 6556                        let blame = blame.read(cx);
 6557                        let details = blame.details_for_entry(&blame_entry);
 6558                        let markdown = cx.new(|cx| {
 6559                            Markdown::new(
 6560                                details
 6561                                    .as_ref()
 6562                                    .map(|message| message.message.clone())
 6563                                    .unwrap_or_default(),
 6564                                None,
 6565                                None,
 6566                                cx,
 6567                            )
 6568                        });
 6569                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6570                            position,
 6571                            hide_task: None,
 6572                            popover_bounds: None,
 6573                            popover_state: InlineBlamePopoverState {
 6574                                scroll_handle: ScrollHandle::new(),
 6575                                commit_message: details,
 6576                                markdown,
 6577                            },
 6578                        });
 6579                        cx.notify();
 6580                    })
 6581                    .ok();
 6582            });
 6583            self.inline_blame_popover_show_task = Some(show_task);
 6584        }
 6585    }
 6586
 6587    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6588        self.inline_blame_popover_show_task.take();
 6589        if let Some(state) = &mut self.inline_blame_popover {
 6590            let hide_task = cx.spawn(async move |editor, cx| {
 6591                cx.background_executor()
 6592                    .timer(std::time::Duration::from_millis(100))
 6593                    .await;
 6594                editor
 6595                    .update(cx, |editor, cx| {
 6596                        editor.inline_blame_popover.take();
 6597                        cx.notify();
 6598                    })
 6599                    .ok();
 6600            });
 6601            state.hide_task = Some(hide_task);
 6602        }
 6603    }
 6604
 6605    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6606        if self.pending_rename.is_some() {
 6607            return None;
 6608        }
 6609
 6610        let provider = self.semantics_provider.clone()?;
 6611        let buffer = self.buffer.read(cx);
 6612        let newest_selection = self.selections.newest_anchor().clone();
 6613        let cursor_position = newest_selection.head();
 6614        let (cursor_buffer, cursor_buffer_position) =
 6615            buffer.text_anchor_for_position(cursor_position, cx)?;
 6616        let (tail_buffer, tail_buffer_position) =
 6617            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6618        if cursor_buffer != tail_buffer {
 6619            return None;
 6620        }
 6621
 6622        let snapshot = cursor_buffer.read(cx).snapshot();
 6623        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6624        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6625        if start_word_range != end_word_range {
 6626            self.document_highlights_task.take();
 6627            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6628            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6629            return None;
 6630        }
 6631
 6632        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6633        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6634            cx.background_executor()
 6635                .timer(Duration::from_millis(debounce))
 6636                .await;
 6637
 6638            let highlights = if let Some(highlights) = cx
 6639                .update(|cx| {
 6640                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6641                })
 6642                .ok()
 6643                .flatten()
 6644            {
 6645                highlights.await.log_err()
 6646            } else {
 6647                None
 6648            };
 6649
 6650            if let Some(highlights) = highlights {
 6651                this.update(cx, |this, cx| {
 6652                    if this.pending_rename.is_some() {
 6653                        return;
 6654                    }
 6655
 6656                    let buffer_id = cursor_position.buffer_id;
 6657                    let buffer = this.buffer.read(cx);
 6658                    if !buffer
 6659                        .text_anchor_for_position(cursor_position, cx)
 6660                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6661                    {
 6662                        return;
 6663                    }
 6664
 6665                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6666                    let mut write_ranges = Vec::new();
 6667                    let mut read_ranges = Vec::new();
 6668                    for highlight in highlights {
 6669                        for (excerpt_id, excerpt_range) in
 6670                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6671                        {
 6672                            let start = highlight
 6673                                .range
 6674                                .start
 6675                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6676                            let end = highlight
 6677                                .range
 6678                                .end
 6679                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6680                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6681                                continue;
 6682                            }
 6683
 6684                            let range = Anchor {
 6685                                buffer_id,
 6686                                excerpt_id,
 6687                                text_anchor: start,
 6688                                diff_base_anchor: None,
 6689                            }..Anchor {
 6690                                buffer_id,
 6691                                excerpt_id,
 6692                                text_anchor: end,
 6693                                diff_base_anchor: None,
 6694                            };
 6695                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6696                                write_ranges.push(range);
 6697                            } else {
 6698                                read_ranges.push(range);
 6699                            }
 6700                        }
 6701                    }
 6702
 6703                    this.highlight_background::<DocumentHighlightRead>(
 6704                        &read_ranges,
 6705                        |theme| theme.colors().editor_document_highlight_read_background,
 6706                        cx,
 6707                    );
 6708                    this.highlight_background::<DocumentHighlightWrite>(
 6709                        &write_ranges,
 6710                        |theme| theme.colors().editor_document_highlight_write_background,
 6711                        cx,
 6712                    );
 6713                    cx.notify();
 6714                })
 6715                .log_err();
 6716            }
 6717        }));
 6718        None
 6719    }
 6720
 6721    fn prepare_highlight_query_from_selection(
 6722        &mut self,
 6723        cx: &mut Context<Editor>,
 6724    ) -> Option<(String, Range<Anchor>)> {
 6725        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6726            return None;
 6727        }
 6728        if !EditorSettings::get_global(cx).selection_highlight {
 6729            return None;
 6730        }
 6731        if self.selections.count() != 1 || self.selections.line_mode {
 6732            return None;
 6733        }
 6734        let selection = self.selections.newest::<Point>(cx);
 6735        if selection.is_empty() || selection.start.row != selection.end.row {
 6736            return None;
 6737        }
 6738        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6739        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6740        let query = multi_buffer_snapshot
 6741            .text_for_range(selection_anchor_range.clone())
 6742            .collect::<String>();
 6743        if query.trim().is_empty() {
 6744            return None;
 6745        }
 6746        Some((query, selection_anchor_range))
 6747    }
 6748
 6749    fn update_selection_occurrence_highlights(
 6750        &mut self,
 6751        query_text: String,
 6752        query_range: Range<Anchor>,
 6753        multi_buffer_range_to_query: Range<Point>,
 6754        use_debounce: bool,
 6755        window: &mut Window,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Task<()> {
 6758        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6759        cx.spawn_in(window, async move |editor, cx| {
 6760            if use_debounce {
 6761                cx.background_executor()
 6762                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6763                    .await;
 6764            }
 6765            let match_task = cx.background_spawn(async move {
 6766                let buffer_ranges = multi_buffer_snapshot
 6767                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6768                    .into_iter()
 6769                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6770                let mut match_ranges = Vec::new();
 6771                let Ok(regex) = project::search::SearchQuery::text(
 6772                    query_text.clone(),
 6773                    false,
 6774                    false,
 6775                    false,
 6776                    Default::default(),
 6777                    Default::default(),
 6778                    false,
 6779                    None,
 6780                ) else {
 6781                    return Vec::default();
 6782                };
 6783                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6784                    match_ranges.extend(
 6785                        regex
 6786                            .search(&buffer_snapshot, Some(search_range.clone()))
 6787                            .await
 6788                            .into_iter()
 6789                            .filter_map(|match_range| {
 6790                                let match_start = buffer_snapshot
 6791                                    .anchor_after(search_range.start + match_range.start);
 6792                                let match_end = buffer_snapshot
 6793                                    .anchor_before(search_range.start + match_range.end);
 6794                                let match_anchor_range = Anchor::range_in_buffer(
 6795                                    excerpt_id,
 6796                                    buffer_snapshot.remote_id(),
 6797                                    match_start..match_end,
 6798                                );
 6799                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6800                            }),
 6801                    );
 6802                }
 6803                match_ranges
 6804            });
 6805            let match_ranges = match_task.await;
 6806            editor
 6807                .update_in(cx, |editor, _, cx| {
 6808                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6809                    if !match_ranges.is_empty() {
 6810                        editor.highlight_background::<SelectedTextHighlight>(
 6811                            &match_ranges,
 6812                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6813                            cx,
 6814                        )
 6815                    }
 6816                })
 6817                .log_err();
 6818        })
 6819    }
 6820
 6821    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6822        struct NewlineFold;
 6823        let type_id = std::any::TypeId::of::<NewlineFold>();
 6824        if !self.mode.is_single_line() {
 6825            return;
 6826        }
 6827        let snapshot = self.snapshot(window, cx);
 6828        if snapshot.buffer_snapshot.max_point().row == 0 {
 6829            return;
 6830        }
 6831        let task = cx.background_spawn(async move {
 6832            let new_newlines = snapshot
 6833                .buffer_chars_at(0)
 6834                .filter_map(|(c, i)| {
 6835                    if c == '\n' {
 6836                        Some(
 6837                            snapshot.buffer_snapshot.anchor_after(i)
 6838                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6839                        )
 6840                    } else {
 6841                        None
 6842                    }
 6843                })
 6844                .collect::<Vec<_>>();
 6845            let existing_newlines = snapshot
 6846                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6847                .filter_map(|fold| {
 6848                    if fold.placeholder.type_tag == Some(type_id) {
 6849                        Some(fold.range.start..fold.range.end)
 6850                    } else {
 6851                        None
 6852                    }
 6853                })
 6854                .collect::<Vec<_>>();
 6855
 6856            (new_newlines, existing_newlines)
 6857        });
 6858        self.folding_newlines = cx.spawn(async move |this, cx| {
 6859            let (new_newlines, existing_newlines) = task.await;
 6860            if new_newlines == existing_newlines {
 6861                return;
 6862            }
 6863            let placeholder = FoldPlaceholder {
 6864                render: Arc::new(move |_, _, cx| {
 6865                    div()
 6866                        .bg(cx.theme().status().hint_background)
 6867                        .border_b_1()
 6868                        .size_full()
 6869                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6870                        .border_color(cx.theme().status().hint)
 6871                        .child("\\n")
 6872                        .into_any()
 6873                }),
 6874                constrain_width: false,
 6875                merge_adjacent: false,
 6876                type_tag: Some(type_id),
 6877            };
 6878            let creases = new_newlines
 6879                .into_iter()
 6880                .map(|range| Crease::simple(range, placeholder.clone()))
 6881                .collect();
 6882            this.update(cx, |this, cx| {
 6883                this.display_map.update(cx, |display_map, cx| {
 6884                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6885                    display_map.fold(creases, cx);
 6886                });
 6887            })
 6888            .ok();
 6889        });
 6890    }
 6891
 6892    fn refresh_selected_text_highlights(
 6893        &mut self,
 6894        on_buffer_edit: bool,
 6895        window: &mut Window,
 6896        cx: &mut Context<Editor>,
 6897    ) {
 6898        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6899        else {
 6900            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6901            self.quick_selection_highlight_task.take();
 6902            self.debounced_selection_highlight_task.take();
 6903            return;
 6904        };
 6905        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6906        if on_buffer_edit
 6907            || self
 6908                .quick_selection_highlight_task
 6909                .as_ref()
 6910                .map_or(true, |(prev_anchor_range, _)| {
 6911                    prev_anchor_range != &query_range
 6912                })
 6913        {
 6914            let multi_buffer_visible_start = self
 6915                .scroll_manager
 6916                .anchor()
 6917                .anchor
 6918                .to_point(&multi_buffer_snapshot);
 6919            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6920                multi_buffer_visible_start
 6921                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6922                Bias::Left,
 6923            );
 6924            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6925            self.quick_selection_highlight_task = Some((
 6926                query_range.clone(),
 6927                self.update_selection_occurrence_highlights(
 6928                    query_text.clone(),
 6929                    query_range.clone(),
 6930                    multi_buffer_visible_range,
 6931                    false,
 6932                    window,
 6933                    cx,
 6934                ),
 6935            ));
 6936        }
 6937        if on_buffer_edit
 6938            || self
 6939                .debounced_selection_highlight_task
 6940                .as_ref()
 6941                .map_or(true, |(prev_anchor_range, _)| {
 6942                    prev_anchor_range != &query_range
 6943                })
 6944        {
 6945            let multi_buffer_start = multi_buffer_snapshot
 6946                .anchor_before(0)
 6947                .to_point(&multi_buffer_snapshot);
 6948            let multi_buffer_end = multi_buffer_snapshot
 6949                .anchor_after(multi_buffer_snapshot.len())
 6950                .to_point(&multi_buffer_snapshot);
 6951            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6952            self.debounced_selection_highlight_task = Some((
 6953                query_range.clone(),
 6954                self.update_selection_occurrence_highlights(
 6955                    query_text,
 6956                    query_range,
 6957                    multi_buffer_full_range,
 6958                    true,
 6959                    window,
 6960                    cx,
 6961                ),
 6962            ));
 6963        }
 6964    }
 6965
 6966    pub fn refresh_inline_completion(
 6967        &mut self,
 6968        debounce: bool,
 6969        user_requested: bool,
 6970        window: &mut Window,
 6971        cx: &mut Context<Self>,
 6972    ) -> Option<()> {
 6973        let provider = self.edit_prediction_provider()?;
 6974        let cursor = self.selections.newest_anchor().head();
 6975        let (buffer, cursor_buffer_position) =
 6976            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6977
 6978        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6979            self.discard_inline_completion(false, cx);
 6980            return None;
 6981        }
 6982
 6983        if !user_requested
 6984            && (!self.should_show_edit_predictions()
 6985                || !self.is_focused(window)
 6986                || buffer.read(cx).is_empty())
 6987        {
 6988            self.discard_inline_completion(false, cx);
 6989            return None;
 6990        }
 6991
 6992        self.update_visible_inline_completion(window, cx);
 6993        provider.refresh(
 6994            self.project.clone(),
 6995            buffer,
 6996            cursor_buffer_position,
 6997            debounce,
 6998            cx,
 6999        );
 7000        Some(())
 7001    }
 7002
 7003    fn show_edit_predictions_in_menu(&self) -> bool {
 7004        match self.edit_prediction_settings {
 7005            EditPredictionSettings::Disabled => false,
 7006            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7007        }
 7008    }
 7009
 7010    pub fn edit_predictions_enabled(&self) -> bool {
 7011        match self.edit_prediction_settings {
 7012            EditPredictionSettings::Disabled => false,
 7013            EditPredictionSettings::Enabled { .. } => true,
 7014        }
 7015    }
 7016
 7017    fn edit_prediction_requires_modifier(&self) -> bool {
 7018        match self.edit_prediction_settings {
 7019            EditPredictionSettings::Disabled => false,
 7020            EditPredictionSettings::Enabled {
 7021                preview_requires_modifier,
 7022                ..
 7023            } => preview_requires_modifier,
 7024        }
 7025    }
 7026
 7027    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7028        if self.edit_prediction_provider.is_none() {
 7029            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7030        } else {
 7031            let selection = self.selections.newest_anchor();
 7032            let cursor = selection.head();
 7033
 7034            if let Some((buffer, cursor_buffer_position)) =
 7035                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7036            {
 7037                self.edit_prediction_settings =
 7038                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7039            }
 7040        }
 7041    }
 7042
 7043    fn edit_prediction_settings_at_position(
 7044        &self,
 7045        buffer: &Entity<Buffer>,
 7046        buffer_position: language::Anchor,
 7047        cx: &App,
 7048    ) -> EditPredictionSettings {
 7049        if !self.mode.is_full()
 7050            || !self.show_inline_completions_override.unwrap_or(true)
 7051            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7052        {
 7053            return EditPredictionSettings::Disabled;
 7054        }
 7055
 7056        let buffer = buffer.read(cx);
 7057
 7058        let file = buffer.file();
 7059
 7060        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7061            return EditPredictionSettings::Disabled;
 7062        };
 7063
 7064        let by_provider = matches!(
 7065            self.menu_inline_completions_policy,
 7066            MenuInlineCompletionsPolicy::ByProvider
 7067        );
 7068
 7069        let show_in_menu = by_provider
 7070            && self
 7071                .edit_prediction_provider
 7072                .as_ref()
 7073                .map_or(false, |provider| {
 7074                    provider.provider.show_completions_in_menu()
 7075                });
 7076
 7077        let preview_requires_modifier =
 7078            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7079
 7080        EditPredictionSettings::Enabled {
 7081            show_in_menu,
 7082            preview_requires_modifier,
 7083        }
 7084    }
 7085
 7086    fn should_show_edit_predictions(&self) -> bool {
 7087        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7088    }
 7089
 7090    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7091        matches!(
 7092            self.edit_prediction_preview,
 7093            EditPredictionPreview::Active { .. }
 7094        )
 7095    }
 7096
 7097    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7098        let cursor = self.selections.newest_anchor().head();
 7099        if let Some((buffer, cursor_position)) =
 7100            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7101        {
 7102            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7103        } else {
 7104            false
 7105        }
 7106    }
 7107
 7108    pub fn supports_minimap(&self, cx: &App) -> bool {
 7109        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7110    }
 7111
 7112    fn edit_predictions_enabled_in_buffer(
 7113        &self,
 7114        buffer: &Entity<Buffer>,
 7115        buffer_position: language::Anchor,
 7116        cx: &App,
 7117    ) -> bool {
 7118        maybe!({
 7119            if self.read_only(cx) {
 7120                return Some(false);
 7121            }
 7122            let provider = self.edit_prediction_provider()?;
 7123            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7124                return Some(false);
 7125            }
 7126            let buffer = buffer.read(cx);
 7127            let Some(file) = buffer.file() else {
 7128                return Some(true);
 7129            };
 7130            let settings = all_language_settings(Some(file), cx);
 7131            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7132        })
 7133        .unwrap_or(false)
 7134    }
 7135
 7136    fn cycle_inline_completion(
 7137        &mut self,
 7138        direction: Direction,
 7139        window: &mut Window,
 7140        cx: &mut Context<Self>,
 7141    ) -> Option<()> {
 7142        let provider = self.edit_prediction_provider()?;
 7143        let cursor = self.selections.newest_anchor().head();
 7144        let (buffer, cursor_buffer_position) =
 7145            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7146        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7147            return None;
 7148        }
 7149
 7150        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7151        self.update_visible_inline_completion(window, cx);
 7152
 7153        Some(())
 7154    }
 7155
 7156    pub fn show_inline_completion(
 7157        &mut self,
 7158        _: &ShowEditPrediction,
 7159        window: &mut Window,
 7160        cx: &mut Context<Self>,
 7161    ) {
 7162        if !self.has_active_inline_completion() {
 7163            self.refresh_inline_completion(false, true, window, cx);
 7164            return;
 7165        }
 7166
 7167        self.update_visible_inline_completion(window, cx);
 7168    }
 7169
 7170    pub fn display_cursor_names(
 7171        &mut self,
 7172        _: &DisplayCursorNames,
 7173        window: &mut Window,
 7174        cx: &mut Context<Self>,
 7175    ) {
 7176        self.show_cursor_names(window, cx);
 7177    }
 7178
 7179    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7180        self.show_cursor_names = true;
 7181        cx.notify();
 7182        cx.spawn_in(window, async move |this, cx| {
 7183            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7184            this.update(cx, |this, cx| {
 7185                this.show_cursor_names = false;
 7186                cx.notify()
 7187            })
 7188            .ok()
 7189        })
 7190        .detach();
 7191    }
 7192
 7193    pub fn next_edit_prediction(
 7194        &mut self,
 7195        _: &NextEditPrediction,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) {
 7199        if self.has_active_inline_completion() {
 7200            self.cycle_inline_completion(Direction::Next, window, cx);
 7201        } else {
 7202            let is_copilot_disabled = self
 7203                .refresh_inline_completion(false, true, window, cx)
 7204                .is_none();
 7205            if is_copilot_disabled {
 7206                cx.propagate();
 7207            }
 7208        }
 7209    }
 7210
 7211    pub fn previous_edit_prediction(
 7212        &mut self,
 7213        _: &PreviousEditPrediction,
 7214        window: &mut Window,
 7215        cx: &mut Context<Self>,
 7216    ) {
 7217        if self.has_active_inline_completion() {
 7218            self.cycle_inline_completion(Direction::Prev, window, cx);
 7219        } else {
 7220            let is_copilot_disabled = self
 7221                .refresh_inline_completion(false, true, window, cx)
 7222                .is_none();
 7223            if is_copilot_disabled {
 7224                cx.propagate();
 7225            }
 7226        }
 7227    }
 7228
 7229    pub fn accept_edit_prediction(
 7230        &mut self,
 7231        _: &AcceptEditPrediction,
 7232        window: &mut Window,
 7233        cx: &mut Context<Self>,
 7234    ) {
 7235        if self.show_edit_predictions_in_menu() {
 7236            self.hide_context_menu(window, cx);
 7237        }
 7238
 7239        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7240            return;
 7241        };
 7242
 7243        self.report_inline_completion_event(
 7244            active_inline_completion.completion_id.clone(),
 7245            true,
 7246            cx,
 7247        );
 7248
 7249        match &active_inline_completion.completion {
 7250            InlineCompletion::Move { target, .. } => {
 7251                let target = *target;
 7252
 7253                if let Some(position_map) = &self.last_position_map {
 7254                    if position_map
 7255                        .visible_row_range
 7256                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7257                        || !self.edit_prediction_requires_modifier()
 7258                    {
 7259                        self.unfold_ranges(&[target..target], true, false, cx);
 7260                        // Note that this is also done in vim's handler of the Tab action.
 7261                        self.change_selections(
 7262                            SelectionEffects::scroll(Autoscroll::newest()),
 7263                            window,
 7264                            cx,
 7265                            |selections| {
 7266                                selections.select_anchor_ranges([target..target]);
 7267                            },
 7268                        );
 7269                        self.clear_row_highlights::<EditPredictionPreview>();
 7270
 7271                        self.edit_prediction_preview
 7272                            .set_previous_scroll_position(None);
 7273                    } else {
 7274                        self.edit_prediction_preview
 7275                            .set_previous_scroll_position(Some(
 7276                                position_map.snapshot.scroll_anchor,
 7277                            ));
 7278
 7279                        self.highlight_rows::<EditPredictionPreview>(
 7280                            target..target,
 7281                            cx.theme().colors().editor_highlighted_line_background,
 7282                            RowHighlightOptions {
 7283                                autoscroll: true,
 7284                                ..Default::default()
 7285                            },
 7286                            cx,
 7287                        );
 7288                        self.request_autoscroll(Autoscroll::fit(), cx);
 7289                    }
 7290                }
 7291            }
 7292            InlineCompletion::Edit { edits, .. } => {
 7293                if let Some(provider) = self.edit_prediction_provider() {
 7294                    provider.accept(cx);
 7295                }
 7296
 7297                // Store the transaction ID and selections before applying the edit
 7298                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7299
 7300                let snapshot = self.buffer.read(cx).snapshot(cx);
 7301                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7302
 7303                self.buffer.update(cx, |buffer, cx| {
 7304                    buffer.edit(edits.iter().cloned(), None, cx)
 7305                });
 7306
 7307                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7308                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7309                });
 7310
 7311                let selections = self.selections.disjoint_anchors();
 7312                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7313                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7314                    if has_new_transaction {
 7315                        self.selection_history
 7316                            .insert_transaction(transaction_id_now, selections);
 7317                    }
 7318                }
 7319
 7320                self.update_visible_inline_completion(window, cx);
 7321                if self.active_inline_completion.is_none() {
 7322                    self.refresh_inline_completion(true, true, window, cx);
 7323                }
 7324
 7325                cx.notify();
 7326            }
 7327        }
 7328
 7329        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7330    }
 7331
 7332    pub fn accept_partial_inline_completion(
 7333        &mut self,
 7334        _: &AcceptPartialEditPrediction,
 7335        window: &mut Window,
 7336        cx: &mut Context<Self>,
 7337    ) {
 7338        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7339            return;
 7340        };
 7341        if self.selections.count() != 1 {
 7342            return;
 7343        }
 7344
 7345        self.report_inline_completion_event(
 7346            active_inline_completion.completion_id.clone(),
 7347            true,
 7348            cx,
 7349        );
 7350
 7351        match &active_inline_completion.completion {
 7352            InlineCompletion::Move { target, .. } => {
 7353                let target = *target;
 7354                self.change_selections(
 7355                    SelectionEffects::scroll(Autoscroll::newest()),
 7356                    window,
 7357                    cx,
 7358                    |selections| {
 7359                        selections.select_anchor_ranges([target..target]);
 7360                    },
 7361                );
 7362            }
 7363            InlineCompletion::Edit { edits, .. } => {
 7364                // Find an insertion that starts at the cursor position.
 7365                let snapshot = self.buffer.read(cx).snapshot(cx);
 7366                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7367                let insertion = edits.iter().find_map(|(range, text)| {
 7368                    let range = range.to_offset(&snapshot);
 7369                    if range.is_empty() && range.start == cursor_offset {
 7370                        Some(text)
 7371                    } else {
 7372                        None
 7373                    }
 7374                });
 7375
 7376                if let Some(text) = insertion {
 7377                    let mut partial_completion = text
 7378                        .chars()
 7379                        .by_ref()
 7380                        .take_while(|c| c.is_alphabetic())
 7381                        .collect::<String>();
 7382                    if partial_completion.is_empty() {
 7383                        partial_completion = text
 7384                            .chars()
 7385                            .by_ref()
 7386                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7387                            .collect::<String>();
 7388                    }
 7389
 7390                    cx.emit(EditorEvent::InputHandled {
 7391                        utf16_range_to_replace: None,
 7392                        text: partial_completion.clone().into(),
 7393                    });
 7394
 7395                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7396
 7397                    self.refresh_inline_completion(true, true, window, cx);
 7398                    cx.notify();
 7399                } else {
 7400                    self.accept_edit_prediction(&Default::default(), window, cx);
 7401                }
 7402            }
 7403        }
 7404    }
 7405
 7406    fn discard_inline_completion(
 7407        &mut self,
 7408        should_report_inline_completion_event: bool,
 7409        cx: &mut Context<Self>,
 7410    ) -> bool {
 7411        if should_report_inline_completion_event {
 7412            let completion_id = self
 7413                .active_inline_completion
 7414                .as_ref()
 7415                .and_then(|active_completion| active_completion.completion_id.clone());
 7416
 7417            self.report_inline_completion_event(completion_id, false, cx);
 7418        }
 7419
 7420        if let Some(provider) = self.edit_prediction_provider() {
 7421            provider.discard(cx);
 7422        }
 7423
 7424        self.take_active_inline_completion(cx)
 7425    }
 7426
 7427    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7428        let Some(provider) = self.edit_prediction_provider() else {
 7429            return;
 7430        };
 7431
 7432        let Some((_, buffer, _)) = self
 7433            .buffer
 7434            .read(cx)
 7435            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7436        else {
 7437            return;
 7438        };
 7439
 7440        let extension = buffer
 7441            .read(cx)
 7442            .file()
 7443            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7444
 7445        let event_type = match accepted {
 7446            true => "Edit Prediction Accepted",
 7447            false => "Edit Prediction Discarded",
 7448        };
 7449        telemetry::event!(
 7450            event_type,
 7451            provider = provider.name(),
 7452            prediction_id = id,
 7453            suggestion_accepted = accepted,
 7454            file_extension = extension,
 7455        );
 7456    }
 7457
 7458    pub fn has_active_inline_completion(&self) -> bool {
 7459        self.active_inline_completion.is_some()
 7460    }
 7461
 7462    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7463        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7464            return false;
 7465        };
 7466
 7467        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7468        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7469        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7470        true
 7471    }
 7472
 7473    /// Returns true when we're displaying the edit prediction popover below the cursor
 7474    /// like we are not previewing and the LSP autocomplete menu is visible
 7475    /// or we are in `when_holding_modifier` mode.
 7476    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7477        if self.edit_prediction_preview_is_active()
 7478            || !self.show_edit_predictions_in_menu()
 7479            || !self.edit_predictions_enabled()
 7480        {
 7481            return false;
 7482        }
 7483
 7484        if self.has_visible_completions_menu() {
 7485            return true;
 7486        }
 7487
 7488        has_completion && self.edit_prediction_requires_modifier()
 7489    }
 7490
 7491    fn handle_modifiers_changed(
 7492        &mut self,
 7493        modifiers: Modifiers,
 7494        position_map: &PositionMap,
 7495        window: &mut Window,
 7496        cx: &mut Context<Self>,
 7497    ) {
 7498        if self.show_edit_predictions_in_menu() {
 7499            self.update_edit_prediction_preview(&modifiers, window, cx);
 7500        }
 7501
 7502        self.update_selection_mode(&modifiers, position_map, window, cx);
 7503
 7504        let mouse_position = window.mouse_position();
 7505        if !position_map.text_hitbox.is_hovered(window) {
 7506            return;
 7507        }
 7508
 7509        self.update_hovered_link(
 7510            position_map.point_for_position(mouse_position),
 7511            &position_map.snapshot,
 7512            modifiers,
 7513            window,
 7514            cx,
 7515        )
 7516    }
 7517
 7518    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7519        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7520        if invert {
 7521            match multi_cursor_setting {
 7522                MultiCursorModifier::Alt => modifiers.alt,
 7523                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7524            }
 7525        } else {
 7526            match multi_cursor_setting {
 7527                MultiCursorModifier::Alt => modifiers.secondary(),
 7528                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7529            }
 7530        }
 7531    }
 7532
 7533    fn columnar_selection_mode(
 7534        modifiers: &Modifiers,
 7535        cx: &mut Context<Self>,
 7536    ) -> Option<ColumnarMode> {
 7537        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7538            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7539                Some(ColumnarMode::FromMouse)
 7540            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7541                Some(ColumnarMode::FromSelection)
 7542            } else {
 7543                None
 7544            }
 7545        } else {
 7546            None
 7547        }
 7548    }
 7549
 7550    fn update_selection_mode(
 7551        &mut self,
 7552        modifiers: &Modifiers,
 7553        position_map: &PositionMap,
 7554        window: &mut Window,
 7555        cx: &mut Context<Self>,
 7556    ) {
 7557        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7558            return;
 7559        };
 7560        if self.selections.pending.is_none() {
 7561            return;
 7562        }
 7563
 7564        let mouse_position = window.mouse_position();
 7565        let point_for_position = position_map.point_for_position(mouse_position);
 7566        let position = point_for_position.previous_valid;
 7567
 7568        self.select(
 7569            SelectPhase::BeginColumnar {
 7570                position,
 7571                reset: false,
 7572                mode,
 7573                goal_column: point_for_position.exact_unclipped.column(),
 7574            },
 7575            window,
 7576            cx,
 7577        );
 7578    }
 7579
 7580    fn update_edit_prediction_preview(
 7581        &mut self,
 7582        modifiers: &Modifiers,
 7583        window: &mut Window,
 7584        cx: &mut Context<Self>,
 7585    ) {
 7586        let mut modifiers_held = false;
 7587        if let Some(accept_keystroke) = self
 7588            .accept_edit_prediction_keybind(false, window, cx)
 7589            .keystroke()
 7590        {
 7591            modifiers_held = modifiers_held
 7592                || (&accept_keystroke.modifiers == modifiers
 7593                    && accept_keystroke.modifiers.modified());
 7594        };
 7595        if let Some(accept_partial_keystroke) = self
 7596            .accept_edit_prediction_keybind(true, window, cx)
 7597            .keystroke()
 7598        {
 7599            modifiers_held = modifiers_held
 7600                || (&accept_partial_keystroke.modifiers == modifiers
 7601                    && accept_partial_keystroke.modifiers.modified());
 7602        }
 7603
 7604        if modifiers_held {
 7605            if matches!(
 7606                self.edit_prediction_preview,
 7607                EditPredictionPreview::Inactive { .. }
 7608            ) {
 7609                self.edit_prediction_preview = EditPredictionPreview::Active {
 7610                    previous_scroll_position: None,
 7611                    since: Instant::now(),
 7612                };
 7613
 7614                self.update_visible_inline_completion(window, cx);
 7615                cx.notify();
 7616            }
 7617        } else if let EditPredictionPreview::Active {
 7618            previous_scroll_position,
 7619            since,
 7620        } = self.edit_prediction_preview
 7621        {
 7622            if let (Some(previous_scroll_position), Some(position_map)) =
 7623                (previous_scroll_position, self.last_position_map.as_ref())
 7624            {
 7625                self.set_scroll_position(
 7626                    previous_scroll_position
 7627                        .scroll_position(&position_map.snapshot.display_snapshot),
 7628                    window,
 7629                    cx,
 7630                );
 7631            }
 7632
 7633            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7634                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7635            };
 7636            self.clear_row_highlights::<EditPredictionPreview>();
 7637            self.update_visible_inline_completion(window, cx);
 7638            cx.notify();
 7639        }
 7640    }
 7641
 7642    fn update_visible_inline_completion(
 7643        &mut self,
 7644        _window: &mut Window,
 7645        cx: &mut Context<Self>,
 7646    ) -> Option<()> {
 7647        let selection = self.selections.newest_anchor();
 7648        let cursor = selection.head();
 7649        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7650        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7651        let excerpt_id = cursor.excerpt_id;
 7652
 7653        let show_in_menu = self.show_edit_predictions_in_menu();
 7654        let completions_menu_has_precedence = !show_in_menu
 7655            && (self.context_menu.borrow().is_some()
 7656                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7657
 7658        if completions_menu_has_precedence
 7659            || !offset_selection.is_empty()
 7660            || self
 7661                .active_inline_completion
 7662                .as_ref()
 7663                .map_or(false, |completion| {
 7664                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7665                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7666                    !invalidation_range.contains(&offset_selection.head())
 7667                })
 7668        {
 7669            self.discard_inline_completion(false, cx);
 7670            return None;
 7671        }
 7672
 7673        self.take_active_inline_completion(cx);
 7674        let Some(provider) = self.edit_prediction_provider() else {
 7675            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7676            return None;
 7677        };
 7678
 7679        let (buffer, cursor_buffer_position) =
 7680            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7681
 7682        self.edit_prediction_settings =
 7683            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7684
 7685        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7686
 7687        if self.edit_prediction_indent_conflict {
 7688            let cursor_point = cursor.to_point(&multibuffer);
 7689
 7690            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7691
 7692            if let Some((_, indent)) = indents.iter().next() {
 7693                if indent.len == cursor_point.column {
 7694                    self.edit_prediction_indent_conflict = false;
 7695                }
 7696            }
 7697        }
 7698
 7699        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7700        let edits = inline_completion
 7701            .edits
 7702            .into_iter()
 7703            .flat_map(|(range, new_text)| {
 7704                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7705                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7706                Some((start..end, new_text))
 7707            })
 7708            .collect::<Vec<_>>();
 7709        if edits.is_empty() {
 7710            return None;
 7711        }
 7712
 7713        let first_edit_start = edits.first().unwrap().0.start;
 7714        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7715        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7716
 7717        let last_edit_end = edits.last().unwrap().0.end;
 7718        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7719        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7720
 7721        let cursor_row = cursor.to_point(&multibuffer).row;
 7722
 7723        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7724
 7725        let mut inlay_ids = Vec::new();
 7726        let invalidation_row_range;
 7727        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7728            Some(cursor_row..edit_end_row)
 7729        } else if cursor_row > edit_end_row {
 7730            Some(edit_start_row..cursor_row)
 7731        } else {
 7732            None
 7733        };
 7734        let is_move =
 7735            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7736        let completion = if is_move {
 7737            invalidation_row_range =
 7738                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7739            let target = first_edit_start;
 7740            InlineCompletion::Move { target, snapshot }
 7741        } else {
 7742            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7743                && !self.inline_completions_hidden_for_vim_mode;
 7744
 7745            if show_completions_in_buffer {
 7746                if edits
 7747                    .iter()
 7748                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7749                {
 7750                    let mut inlays = Vec::new();
 7751                    for (range, new_text) in &edits {
 7752                        let inlay = Inlay::inline_completion(
 7753                            post_inc(&mut self.next_inlay_id),
 7754                            range.start,
 7755                            new_text.as_str(),
 7756                        );
 7757                        inlay_ids.push(inlay.id);
 7758                        inlays.push(inlay);
 7759                    }
 7760
 7761                    self.splice_inlays(&[], inlays, cx);
 7762                } else {
 7763                    let background_color = cx.theme().status().deleted_background;
 7764                    self.highlight_text::<InlineCompletionHighlight>(
 7765                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7766                        HighlightStyle {
 7767                            background_color: Some(background_color),
 7768                            ..Default::default()
 7769                        },
 7770                        cx,
 7771                    );
 7772                }
 7773            }
 7774
 7775            invalidation_row_range = edit_start_row..edit_end_row;
 7776
 7777            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7778                if provider.show_tab_accept_marker() {
 7779                    EditDisplayMode::TabAccept
 7780                } else {
 7781                    EditDisplayMode::Inline
 7782                }
 7783            } else {
 7784                EditDisplayMode::DiffPopover
 7785            };
 7786
 7787            InlineCompletion::Edit {
 7788                edits,
 7789                edit_preview: inline_completion.edit_preview,
 7790                display_mode,
 7791                snapshot,
 7792            }
 7793        };
 7794
 7795        let invalidation_range = multibuffer
 7796            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7797            ..multibuffer.anchor_after(Point::new(
 7798                invalidation_row_range.end,
 7799                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7800            ));
 7801
 7802        self.stale_inline_completion_in_menu = None;
 7803        self.active_inline_completion = Some(InlineCompletionState {
 7804            inlay_ids,
 7805            completion,
 7806            completion_id: inline_completion.id,
 7807            invalidation_range,
 7808        });
 7809
 7810        cx.notify();
 7811
 7812        Some(())
 7813    }
 7814
 7815    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7816        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7817    }
 7818
 7819    fn clear_tasks(&mut self) {
 7820        self.tasks.clear()
 7821    }
 7822
 7823    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7824        if self.tasks.insert(key, value).is_some() {
 7825            // This case should hopefully be rare, but just in case...
 7826            log::error!(
 7827                "multiple different run targets found on a single line, only the last target will be rendered"
 7828            )
 7829        }
 7830    }
 7831
 7832    /// Get all display points of breakpoints that will be rendered within editor
 7833    ///
 7834    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7835    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7836    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7837    fn active_breakpoints(
 7838        &self,
 7839        range: Range<DisplayRow>,
 7840        window: &mut Window,
 7841        cx: &mut Context<Self>,
 7842    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7843        let mut breakpoint_display_points = HashMap::default();
 7844
 7845        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7846            return breakpoint_display_points;
 7847        };
 7848
 7849        let snapshot = self.snapshot(window, cx);
 7850
 7851        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7852        let Some(project) = self.project.as_ref() else {
 7853            return breakpoint_display_points;
 7854        };
 7855
 7856        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7857            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7858
 7859        for (buffer_snapshot, range, excerpt_id) in
 7860            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7861        {
 7862            let Some(buffer) = project
 7863                .read(cx)
 7864                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7865            else {
 7866                continue;
 7867            };
 7868            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7869                &buffer,
 7870                Some(
 7871                    buffer_snapshot.anchor_before(range.start)
 7872                        ..buffer_snapshot.anchor_after(range.end),
 7873                ),
 7874                buffer_snapshot,
 7875                cx,
 7876            );
 7877            for (breakpoint, state) in breakpoints {
 7878                let multi_buffer_anchor =
 7879                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7880                let position = multi_buffer_anchor
 7881                    .to_point(&multi_buffer_snapshot)
 7882                    .to_display_point(&snapshot);
 7883
 7884                breakpoint_display_points.insert(
 7885                    position.row(),
 7886                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7887                );
 7888            }
 7889        }
 7890
 7891        breakpoint_display_points
 7892    }
 7893
 7894    fn breakpoint_context_menu(
 7895        &self,
 7896        anchor: Anchor,
 7897        window: &mut Window,
 7898        cx: &mut Context<Self>,
 7899    ) -> Entity<ui::ContextMenu> {
 7900        let weak_editor = cx.weak_entity();
 7901        let focus_handle = self.focus_handle(cx);
 7902
 7903        let row = self
 7904            .buffer
 7905            .read(cx)
 7906            .snapshot(cx)
 7907            .summary_for_anchor::<Point>(&anchor)
 7908            .row;
 7909
 7910        let breakpoint = self
 7911            .breakpoint_at_row(row, window, cx)
 7912            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7913
 7914        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7915            "Edit Log Breakpoint"
 7916        } else {
 7917            "Set Log Breakpoint"
 7918        };
 7919
 7920        let condition_breakpoint_msg = if breakpoint
 7921            .as_ref()
 7922            .is_some_and(|bp| bp.1.condition.is_some())
 7923        {
 7924            "Edit Condition Breakpoint"
 7925        } else {
 7926            "Set Condition Breakpoint"
 7927        };
 7928
 7929        let hit_condition_breakpoint_msg = if breakpoint
 7930            .as_ref()
 7931            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7932        {
 7933            "Edit Hit Condition Breakpoint"
 7934        } else {
 7935            "Set Hit Condition Breakpoint"
 7936        };
 7937
 7938        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7939            "Unset Breakpoint"
 7940        } else {
 7941            "Set Breakpoint"
 7942        };
 7943
 7944        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7945
 7946        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7947            BreakpointState::Enabled => Some("Disable"),
 7948            BreakpointState::Disabled => Some("Enable"),
 7949        });
 7950
 7951        let (anchor, breakpoint) =
 7952            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7953
 7954        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7955            menu.on_blur_subscription(Subscription::new(|| {}))
 7956                .context(focus_handle)
 7957                .when(run_to_cursor, |this| {
 7958                    let weak_editor = weak_editor.clone();
 7959                    this.entry("Run to cursor", None, move |window, cx| {
 7960                        weak_editor
 7961                            .update(cx, |editor, cx| {
 7962                                editor.change_selections(
 7963                                    SelectionEffects::no_scroll(),
 7964                                    window,
 7965                                    cx,
 7966                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7967                                );
 7968                            })
 7969                            .ok();
 7970
 7971                        window.dispatch_action(Box::new(RunToCursor), cx);
 7972                    })
 7973                    .separator()
 7974                })
 7975                .when_some(toggle_state_msg, |this, msg| {
 7976                    this.entry(msg, None, {
 7977                        let weak_editor = weak_editor.clone();
 7978                        let breakpoint = breakpoint.clone();
 7979                        move |_window, cx| {
 7980                            weak_editor
 7981                                .update(cx, |this, cx| {
 7982                                    this.edit_breakpoint_at_anchor(
 7983                                        anchor,
 7984                                        breakpoint.as_ref().clone(),
 7985                                        BreakpointEditAction::InvertState,
 7986                                        cx,
 7987                                    );
 7988                                })
 7989                                .log_err();
 7990                        }
 7991                    })
 7992                })
 7993                .entry(set_breakpoint_msg, None, {
 7994                    let weak_editor = weak_editor.clone();
 7995                    let breakpoint = breakpoint.clone();
 7996                    move |_window, cx| {
 7997                        weak_editor
 7998                            .update(cx, |this, cx| {
 7999                                this.edit_breakpoint_at_anchor(
 8000                                    anchor,
 8001                                    breakpoint.as_ref().clone(),
 8002                                    BreakpointEditAction::Toggle,
 8003                                    cx,
 8004                                );
 8005                            })
 8006                            .log_err();
 8007                    }
 8008                })
 8009                .entry(log_breakpoint_msg, None, {
 8010                    let breakpoint = breakpoint.clone();
 8011                    let weak_editor = weak_editor.clone();
 8012                    move |window, cx| {
 8013                        weak_editor
 8014                            .update(cx, |this, cx| {
 8015                                this.add_edit_breakpoint_block(
 8016                                    anchor,
 8017                                    breakpoint.as_ref(),
 8018                                    BreakpointPromptEditAction::Log,
 8019                                    window,
 8020                                    cx,
 8021                                );
 8022                            })
 8023                            .log_err();
 8024                    }
 8025                })
 8026                .entry(condition_breakpoint_msg, None, {
 8027                    let breakpoint = breakpoint.clone();
 8028                    let weak_editor = weak_editor.clone();
 8029                    move |window, cx| {
 8030                        weak_editor
 8031                            .update(cx, |this, cx| {
 8032                                this.add_edit_breakpoint_block(
 8033                                    anchor,
 8034                                    breakpoint.as_ref(),
 8035                                    BreakpointPromptEditAction::Condition,
 8036                                    window,
 8037                                    cx,
 8038                                );
 8039                            })
 8040                            .log_err();
 8041                    }
 8042                })
 8043                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8044                    weak_editor
 8045                        .update(cx, |this, cx| {
 8046                            this.add_edit_breakpoint_block(
 8047                                anchor,
 8048                                breakpoint.as_ref(),
 8049                                BreakpointPromptEditAction::HitCondition,
 8050                                window,
 8051                                cx,
 8052                            );
 8053                        })
 8054                        .log_err();
 8055                })
 8056        })
 8057    }
 8058
 8059    fn render_breakpoint(
 8060        &self,
 8061        position: Anchor,
 8062        row: DisplayRow,
 8063        breakpoint: &Breakpoint,
 8064        state: Option<BreakpointSessionState>,
 8065        cx: &mut Context<Self>,
 8066    ) -> IconButton {
 8067        let is_rejected = state.is_some_and(|s| !s.verified);
 8068        // Is it a breakpoint that shows up when hovering over gutter?
 8069        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8070            (false, false),
 8071            |PhantomBreakpointIndicator {
 8072                 is_active,
 8073                 display_row,
 8074                 collides_with_existing_breakpoint,
 8075             }| {
 8076                (
 8077                    is_active && display_row == row,
 8078                    collides_with_existing_breakpoint,
 8079                )
 8080            },
 8081        );
 8082
 8083        let (color, icon) = {
 8084            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8085                (false, false) => ui::IconName::DebugBreakpoint,
 8086                (true, false) => ui::IconName::DebugLogBreakpoint,
 8087                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8088                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8089            };
 8090
 8091            let color = if is_phantom {
 8092                Color::Hint
 8093            } else if is_rejected {
 8094                Color::Disabled
 8095            } else {
 8096                Color::Debugger
 8097            };
 8098
 8099            (color, icon)
 8100        };
 8101
 8102        let breakpoint = Arc::from(breakpoint.clone());
 8103
 8104        let alt_as_text = gpui::Keystroke {
 8105            modifiers: Modifiers::secondary_key(),
 8106            ..Default::default()
 8107        };
 8108        let primary_action_text = if breakpoint.is_disabled() {
 8109            "Enable breakpoint"
 8110        } else if is_phantom && !collides_with_existing {
 8111            "Set breakpoint"
 8112        } else {
 8113            "Unset breakpoint"
 8114        };
 8115        let focus_handle = self.focus_handle.clone();
 8116
 8117        let meta = if is_rejected {
 8118            SharedString::from("No executable code is associated with this line.")
 8119        } else if collides_with_existing && !breakpoint.is_disabled() {
 8120            SharedString::from(format!(
 8121                "{alt_as_text}-click to disable,\nright-click for more options."
 8122            ))
 8123        } else {
 8124            SharedString::from("Right-click for more options.")
 8125        };
 8126        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8127            .icon_size(IconSize::XSmall)
 8128            .size(ui::ButtonSize::None)
 8129            .when(is_rejected, |this| {
 8130                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8131            })
 8132            .icon_color(color)
 8133            .style(ButtonStyle::Transparent)
 8134            .on_click(cx.listener({
 8135                let breakpoint = breakpoint.clone();
 8136
 8137                move |editor, event: &ClickEvent, window, cx| {
 8138                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8139                        BreakpointEditAction::InvertState
 8140                    } else {
 8141                        BreakpointEditAction::Toggle
 8142                    };
 8143
 8144                    window.focus(&editor.focus_handle(cx));
 8145                    editor.edit_breakpoint_at_anchor(
 8146                        position,
 8147                        breakpoint.as_ref().clone(),
 8148                        edit_action,
 8149                        cx,
 8150                    );
 8151                }
 8152            }))
 8153            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8154                editor.set_breakpoint_context_menu(
 8155                    row,
 8156                    Some(position),
 8157                    event.down.position,
 8158                    window,
 8159                    cx,
 8160                );
 8161            }))
 8162            .tooltip(move |window, cx| {
 8163                Tooltip::with_meta_in(
 8164                    primary_action_text,
 8165                    Some(&ToggleBreakpoint),
 8166                    meta.clone(),
 8167                    &focus_handle,
 8168                    window,
 8169                    cx,
 8170                )
 8171            })
 8172    }
 8173
 8174    fn build_tasks_context(
 8175        project: &Entity<Project>,
 8176        buffer: &Entity<Buffer>,
 8177        buffer_row: u32,
 8178        tasks: &Arc<RunnableTasks>,
 8179        cx: &mut Context<Self>,
 8180    ) -> Task<Option<task::TaskContext>> {
 8181        let position = Point::new(buffer_row, tasks.column);
 8182        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8183        let location = Location {
 8184            buffer: buffer.clone(),
 8185            range: range_start..range_start,
 8186        };
 8187        // Fill in the environmental variables from the tree-sitter captures
 8188        let mut captured_task_variables = TaskVariables::default();
 8189        for (capture_name, value) in tasks.extra_variables.clone() {
 8190            captured_task_variables.insert(
 8191                task::VariableName::Custom(capture_name.into()),
 8192                value.clone(),
 8193            );
 8194        }
 8195        project.update(cx, |project, cx| {
 8196            project.task_store().update(cx, |task_store, cx| {
 8197                task_store.task_context_for_location(captured_task_variables, location, cx)
 8198            })
 8199        })
 8200    }
 8201
 8202    pub fn spawn_nearest_task(
 8203        &mut self,
 8204        action: &SpawnNearestTask,
 8205        window: &mut Window,
 8206        cx: &mut Context<Self>,
 8207    ) {
 8208        let Some((workspace, _)) = self.workspace.clone() else {
 8209            return;
 8210        };
 8211        let Some(project) = self.project.clone() else {
 8212            return;
 8213        };
 8214
 8215        // Try to find a closest, enclosing node using tree-sitter that has a
 8216        // task
 8217        let Some((buffer, buffer_row, tasks)) = self
 8218            .find_enclosing_node_task(cx)
 8219            // Or find the task that's closest in row-distance.
 8220            .or_else(|| self.find_closest_task(cx))
 8221        else {
 8222            return;
 8223        };
 8224
 8225        let reveal_strategy = action.reveal;
 8226        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8227        cx.spawn_in(window, async move |_, cx| {
 8228            let context = task_context.await?;
 8229            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8230
 8231            let resolved = &mut resolved_task.resolved;
 8232            resolved.reveal = reveal_strategy;
 8233
 8234            workspace
 8235                .update_in(cx, |workspace, window, cx| {
 8236                    workspace.schedule_resolved_task(
 8237                        task_source_kind,
 8238                        resolved_task,
 8239                        false,
 8240                        window,
 8241                        cx,
 8242                    );
 8243                })
 8244                .ok()
 8245        })
 8246        .detach();
 8247    }
 8248
 8249    fn find_closest_task(
 8250        &mut self,
 8251        cx: &mut Context<Self>,
 8252    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8253        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8254
 8255        let ((buffer_id, row), tasks) = self
 8256            .tasks
 8257            .iter()
 8258            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8259
 8260        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8261        let tasks = Arc::new(tasks.to_owned());
 8262        Some((buffer, *row, tasks))
 8263    }
 8264
 8265    fn find_enclosing_node_task(
 8266        &mut self,
 8267        cx: &mut Context<Self>,
 8268    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8269        let snapshot = self.buffer.read(cx).snapshot(cx);
 8270        let offset = self.selections.newest::<usize>(cx).head();
 8271        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8272        let buffer_id = excerpt.buffer().remote_id();
 8273
 8274        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8275        let mut cursor = layer.node().walk();
 8276
 8277        while cursor.goto_first_child_for_byte(offset).is_some() {
 8278            if cursor.node().end_byte() == offset {
 8279                cursor.goto_next_sibling();
 8280            }
 8281        }
 8282
 8283        // Ascend to the smallest ancestor that contains the range and has a task.
 8284        loop {
 8285            let node = cursor.node();
 8286            let node_range = node.byte_range();
 8287            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8288
 8289            // Check if this node contains our offset
 8290            if node_range.start <= offset && node_range.end >= offset {
 8291                // If it contains offset, check for task
 8292                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8293                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8294                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8295                }
 8296            }
 8297
 8298            if !cursor.goto_parent() {
 8299                break;
 8300            }
 8301        }
 8302        None
 8303    }
 8304
 8305    fn render_run_indicator(
 8306        &self,
 8307        _style: &EditorStyle,
 8308        is_active: bool,
 8309        row: DisplayRow,
 8310        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8311        cx: &mut Context<Self>,
 8312    ) -> IconButton {
 8313        let color = Color::Muted;
 8314        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8315
 8316        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8317            .shape(ui::IconButtonShape::Square)
 8318            .icon_size(IconSize::XSmall)
 8319            .icon_color(color)
 8320            .toggle_state(is_active)
 8321            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8322                let quick_launch = e.down.button == MouseButton::Left;
 8323                window.focus(&editor.focus_handle(cx));
 8324                editor.toggle_code_actions(
 8325                    &ToggleCodeActions {
 8326                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8327                        quick_launch,
 8328                    },
 8329                    window,
 8330                    cx,
 8331                );
 8332            }))
 8333            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8334                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8335            }))
 8336    }
 8337
 8338    pub fn context_menu_visible(&self) -> bool {
 8339        !self.edit_prediction_preview_is_active()
 8340            && self
 8341                .context_menu
 8342                .borrow()
 8343                .as_ref()
 8344                .map_or(false, |menu| menu.visible())
 8345    }
 8346
 8347    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8348        self.context_menu
 8349            .borrow()
 8350            .as_ref()
 8351            .map(|menu| menu.origin())
 8352    }
 8353
 8354    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8355        self.context_menu_options = Some(options);
 8356    }
 8357
 8358    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8359    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8360
 8361    fn render_edit_prediction_popover(
 8362        &mut self,
 8363        text_bounds: &Bounds<Pixels>,
 8364        content_origin: gpui::Point<Pixels>,
 8365        right_margin: Pixels,
 8366        editor_snapshot: &EditorSnapshot,
 8367        visible_row_range: Range<DisplayRow>,
 8368        scroll_top: f32,
 8369        scroll_bottom: f32,
 8370        line_layouts: &[LineWithInvisibles],
 8371        line_height: Pixels,
 8372        scroll_pixel_position: gpui::Point<Pixels>,
 8373        newest_selection_head: Option<DisplayPoint>,
 8374        editor_width: Pixels,
 8375        style: &EditorStyle,
 8376        window: &mut Window,
 8377        cx: &mut App,
 8378    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8379        if self.mode().is_minimap() {
 8380            return None;
 8381        }
 8382        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8383
 8384        if self.edit_prediction_visible_in_cursor_popover(true) {
 8385            return None;
 8386        }
 8387
 8388        match &active_inline_completion.completion {
 8389            InlineCompletion::Move { target, .. } => {
 8390                let target_display_point = target.to_display_point(editor_snapshot);
 8391
 8392                if self.edit_prediction_requires_modifier() {
 8393                    if !self.edit_prediction_preview_is_active() {
 8394                        return None;
 8395                    }
 8396
 8397                    self.render_edit_prediction_modifier_jump_popover(
 8398                        text_bounds,
 8399                        content_origin,
 8400                        visible_row_range,
 8401                        line_layouts,
 8402                        line_height,
 8403                        scroll_pixel_position,
 8404                        newest_selection_head,
 8405                        target_display_point,
 8406                        window,
 8407                        cx,
 8408                    )
 8409                } else {
 8410                    self.render_edit_prediction_eager_jump_popover(
 8411                        text_bounds,
 8412                        content_origin,
 8413                        editor_snapshot,
 8414                        visible_row_range,
 8415                        scroll_top,
 8416                        scroll_bottom,
 8417                        line_height,
 8418                        scroll_pixel_position,
 8419                        target_display_point,
 8420                        editor_width,
 8421                        window,
 8422                        cx,
 8423                    )
 8424                }
 8425            }
 8426            InlineCompletion::Edit {
 8427                display_mode: EditDisplayMode::Inline,
 8428                ..
 8429            } => None,
 8430            InlineCompletion::Edit {
 8431                display_mode: EditDisplayMode::TabAccept,
 8432                edits,
 8433                ..
 8434            } => {
 8435                let range = &edits.first()?.0;
 8436                let target_display_point = range.end.to_display_point(editor_snapshot);
 8437
 8438                self.render_edit_prediction_end_of_line_popover(
 8439                    "Accept",
 8440                    editor_snapshot,
 8441                    visible_row_range,
 8442                    target_display_point,
 8443                    line_height,
 8444                    scroll_pixel_position,
 8445                    content_origin,
 8446                    editor_width,
 8447                    window,
 8448                    cx,
 8449                )
 8450            }
 8451            InlineCompletion::Edit {
 8452                edits,
 8453                edit_preview,
 8454                display_mode: EditDisplayMode::DiffPopover,
 8455                snapshot,
 8456            } => self.render_edit_prediction_diff_popover(
 8457                text_bounds,
 8458                content_origin,
 8459                right_margin,
 8460                editor_snapshot,
 8461                visible_row_range,
 8462                line_layouts,
 8463                line_height,
 8464                scroll_pixel_position,
 8465                newest_selection_head,
 8466                editor_width,
 8467                style,
 8468                edits,
 8469                edit_preview,
 8470                snapshot,
 8471                window,
 8472                cx,
 8473            ),
 8474        }
 8475    }
 8476
 8477    fn render_edit_prediction_modifier_jump_popover(
 8478        &mut self,
 8479        text_bounds: &Bounds<Pixels>,
 8480        content_origin: gpui::Point<Pixels>,
 8481        visible_row_range: Range<DisplayRow>,
 8482        line_layouts: &[LineWithInvisibles],
 8483        line_height: Pixels,
 8484        scroll_pixel_position: gpui::Point<Pixels>,
 8485        newest_selection_head: Option<DisplayPoint>,
 8486        target_display_point: DisplayPoint,
 8487        window: &mut Window,
 8488        cx: &mut App,
 8489    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8490        let scrolled_content_origin =
 8491            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8492
 8493        const SCROLL_PADDING_Y: Pixels = px(12.);
 8494
 8495        if target_display_point.row() < visible_row_range.start {
 8496            return self.render_edit_prediction_scroll_popover(
 8497                |_| SCROLL_PADDING_Y,
 8498                IconName::ArrowUp,
 8499                visible_row_range,
 8500                line_layouts,
 8501                newest_selection_head,
 8502                scrolled_content_origin,
 8503                window,
 8504                cx,
 8505            );
 8506        } else if target_display_point.row() >= visible_row_range.end {
 8507            return self.render_edit_prediction_scroll_popover(
 8508                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8509                IconName::ArrowDown,
 8510                visible_row_range,
 8511                line_layouts,
 8512                newest_selection_head,
 8513                scrolled_content_origin,
 8514                window,
 8515                cx,
 8516            );
 8517        }
 8518
 8519        const POLE_WIDTH: Pixels = px(2.);
 8520
 8521        let line_layout =
 8522            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8523        let target_column = target_display_point.column() as usize;
 8524
 8525        let target_x = line_layout.x_for_index(target_column);
 8526        let target_y =
 8527            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8528
 8529        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8530
 8531        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8532        border_color.l += 0.001;
 8533
 8534        let mut element = v_flex()
 8535            .items_end()
 8536            .when(flag_on_right, |el| el.items_start())
 8537            .child(if flag_on_right {
 8538                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8539                    .rounded_bl(px(0.))
 8540                    .rounded_tl(px(0.))
 8541                    .border_l_2()
 8542                    .border_color(border_color)
 8543            } else {
 8544                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8545                    .rounded_br(px(0.))
 8546                    .rounded_tr(px(0.))
 8547                    .border_r_2()
 8548                    .border_color(border_color)
 8549            })
 8550            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8551            .into_any();
 8552
 8553        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8554
 8555        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8556            - point(
 8557                if flag_on_right {
 8558                    POLE_WIDTH
 8559                } else {
 8560                    size.width - POLE_WIDTH
 8561                },
 8562                size.height - line_height,
 8563            );
 8564
 8565        origin.x = origin.x.max(content_origin.x);
 8566
 8567        element.prepaint_at(origin, window, cx);
 8568
 8569        Some((element, origin))
 8570    }
 8571
 8572    fn render_edit_prediction_scroll_popover(
 8573        &mut self,
 8574        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8575        scroll_icon: IconName,
 8576        visible_row_range: Range<DisplayRow>,
 8577        line_layouts: &[LineWithInvisibles],
 8578        newest_selection_head: Option<DisplayPoint>,
 8579        scrolled_content_origin: gpui::Point<Pixels>,
 8580        window: &mut Window,
 8581        cx: &mut App,
 8582    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8583        let mut element = self
 8584            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8585            .into_any();
 8586
 8587        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8588
 8589        let cursor = newest_selection_head?;
 8590        let cursor_row_layout =
 8591            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8592        let cursor_column = cursor.column() as usize;
 8593
 8594        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8595
 8596        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8597
 8598        element.prepaint_at(origin, window, cx);
 8599        Some((element, origin))
 8600    }
 8601
 8602    fn render_edit_prediction_eager_jump_popover(
 8603        &mut self,
 8604        text_bounds: &Bounds<Pixels>,
 8605        content_origin: gpui::Point<Pixels>,
 8606        editor_snapshot: &EditorSnapshot,
 8607        visible_row_range: Range<DisplayRow>,
 8608        scroll_top: f32,
 8609        scroll_bottom: f32,
 8610        line_height: Pixels,
 8611        scroll_pixel_position: gpui::Point<Pixels>,
 8612        target_display_point: DisplayPoint,
 8613        editor_width: Pixels,
 8614        window: &mut Window,
 8615        cx: &mut App,
 8616    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8617        if target_display_point.row().as_f32() < scroll_top {
 8618            let mut element = self
 8619                .render_edit_prediction_line_popover(
 8620                    "Jump to Edit",
 8621                    Some(IconName::ArrowUp),
 8622                    window,
 8623                    cx,
 8624                )?
 8625                .into_any();
 8626
 8627            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8628            let offset = point(
 8629                (text_bounds.size.width - size.width) / 2.,
 8630                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8631            );
 8632
 8633            let origin = text_bounds.origin + offset;
 8634            element.prepaint_at(origin, window, cx);
 8635            Some((element, origin))
 8636        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8637            let mut element = self
 8638                .render_edit_prediction_line_popover(
 8639                    "Jump to Edit",
 8640                    Some(IconName::ArrowDown),
 8641                    window,
 8642                    cx,
 8643                )?
 8644                .into_any();
 8645
 8646            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8647            let offset = point(
 8648                (text_bounds.size.width - size.width) / 2.,
 8649                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8650            );
 8651
 8652            let origin = text_bounds.origin + offset;
 8653            element.prepaint_at(origin, window, cx);
 8654            Some((element, origin))
 8655        } else {
 8656            self.render_edit_prediction_end_of_line_popover(
 8657                "Jump to Edit",
 8658                editor_snapshot,
 8659                visible_row_range,
 8660                target_display_point,
 8661                line_height,
 8662                scroll_pixel_position,
 8663                content_origin,
 8664                editor_width,
 8665                window,
 8666                cx,
 8667            )
 8668        }
 8669    }
 8670
 8671    fn render_edit_prediction_end_of_line_popover(
 8672        self: &mut Editor,
 8673        label: &'static str,
 8674        editor_snapshot: &EditorSnapshot,
 8675        visible_row_range: Range<DisplayRow>,
 8676        target_display_point: DisplayPoint,
 8677        line_height: Pixels,
 8678        scroll_pixel_position: gpui::Point<Pixels>,
 8679        content_origin: gpui::Point<Pixels>,
 8680        editor_width: Pixels,
 8681        window: &mut Window,
 8682        cx: &mut App,
 8683    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8684        let target_line_end = DisplayPoint::new(
 8685            target_display_point.row(),
 8686            editor_snapshot.line_len(target_display_point.row()),
 8687        );
 8688
 8689        let mut element = self
 8690            .render_edit_prediction_line_popover(label, None, window, cx)?
 8691            .into_any();
 8692
 8693        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8694
 8695        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8696
 8697        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8698        let mut origin = start_point
 8699            + line_origin
 8700            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8701        origin.x = origin.x.max(content_origin.x);
 8702
 8703        let max_x = content_origin.x + editor_width - size.width;
 8704
 8705        if origin.x > max_x {
 8706            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8707
 8708            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8709                origin.y += offset;
 8710                IconName::ArrowUp
 8711            } else {
 8712                origin.y -= offset;
 8713                IconName::ArrowDown
 8714            };
 8715
 8716            element = self
 8717                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8718                .into_any();
 8719
 8720            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8721
 8722            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8723        }
 8724
 8725        element.prepaint_at(origin, window, cx);
 8726        Some((element, origin))
 8727    }
 8728
 8729    fn render_edit_prediction_diff_popover(
 8730        self: &Editor,
 8731        text_bounds: &Bounds<Pixels>,
 8732        content_origin: gpui::Point<Pixels>,
 8733        right_margin: Pixels,
 8734        editor_snapshot: &EditorSnapshot,
 8735        visible_row_range: Range<DisplayRow>,
 8736        line_layouts: &[LineWithInvisibles],
 8737        line_height: Pixels,
 8738        scroll_pixel_position: gpui::Point<Pixels>,
 8739        newest_selection_head: Option<DisplayPoint>,
 8740        editor_width: Pixels,
 8741        style: &EditorStyle,
 8742        edits: &Vec<(Range<Anchor>, String)>,
 8743        edit_preview: &Option<language::EditPreview>,
 8744        snapshot: &language::BufferSnapshot,
 8745        window: &mut Window,
 8746        cx: &mut App,
 8747    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8748        let edit_start = edits
 8749            .first()
 8750            .unwrap()
 8751            .0
 8752            .start
 8753            .to_display_point(editor_snapshot);
 8754        let edit_end = edits
 8755            .last()
 8756            .unwrap()
 8757            .0
 8758            .end
 8759            .to_display_point(editor_snapshot);
 8760
 8761        let is_visible = visible_row_range.contains(&edit_start.row())
 8762            || visible_row_range.contains(&edit_end.row());
 8763        if !is_visible {
 8764            return None;
 8765        }
 8766
 8767        let highlighted_edits =
 8768            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8769
 8770        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8771        let line_count = highlighted_edits.text.lines().count();
 8772
 8773        const BORDER_WIDTH: Pixels = px(1.);
 8774
 8775        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8776        let has_keybind = keybind.is_some();
 8777
 8778        let mut element = h_flex()
 8779            .items_start()
 8780            .child(
 8781                h_flex()
 8782                    .bg(cx.theme().colors().editor_background)
 8783                    .border(BORDER_WIDTH)
 8784                    .shadow_xs()
 8785                    .border_color(cx.theme().colors().border)
 8786                    .rounded_l_lg()
 8787                    .when(line_count > 1, |el| el.rounded_br_lg())
 8788                    .pr_1()
 8789                    .child(styled_text),
 8790            )
 8791            .child(
 8792                h_flex()
 8793                    .h(line_height + BORDER_WIDTH * 2.)
 8794                    .px_1p5()
 8795                    .gap_1()
 8796                    // Workaround: For some reason, there's a gap if we don't do this
 8797                    .ml(-BORDER_WIDTH)
 8798                    .shadow(vec![gpui::BoxShadow {
 8799                        color: gpui::black().opacity(0.05),
 8800                        offset: point(px(1.), px(1.)),
 8801                        blur_radius: px(2.),
 8802                        spread_radius: px(0.),
 8803                    }])
 8804                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8805                    .border(BORDER_WIDTH)
 8806                    .border_color(cx.theme().colors().border)
 8807                    .rounded_r_lg()
 8808                    .id("edit_prediction_diff_popover_keybind")
 8809                    .when(!has_keybind, |el| {
 8810                        let status_colors = cx.theme().status();
 8811
 8812                        el.bg(status_colors.error_background)
 8813                            .border_color(status_colors.error.opacity(0.6))
 8814                            .child(Icon::new(IconName::Info).color(Color::Error))
 8815                            .cursor_default()
 8816                            .hoverable_tooltip(move |_window, cx| {
 8817                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8818                            })
 8819                    })
 8820                    .children(keybind),
 8821            )
 8822            .into_any();
 8823
 8824        let longest_row =
 8825            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8826        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8827            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8828        } else {
 8829            layout_line(
 8830                longest_row,
 8831                editor_snapshot,
 8832                style,
 8833                editor_width,
 8834                |_| false,
 8835                window,
 8836                cx,
 8837            )
 8838            .width
 8839        };
 8840
 8841        let viewport_bounds =
 8842            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8843                right: -right_margin,
 8844                ..Default::default()
 8845            });
 8846
 8847        let x_after_longest =
 8848            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8849                - scroll_pixel_position.x;
 8850
 8851        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853        // Fully visible if it can be displayed within the window (allow overlapping other
 8854        // panes). However, this is only allowed if the popover starts within text_bounds.
 8855        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8856            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8857
 8858        let mut origin = if can_position_to_the_right {
 8859            point(
 8860                x_after_longest,
 8861                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8862                    - scroll_pixel_position.y,
 8863            )
 8864        } else {
 8865            let cursor_row = newest_selection_head.map(|head| head.row());
 8866            let above_edit = edit_start
 8867                .row()
 8868                .0
 8869                .checked_sub(line_count as u32)
 8870                .map(DisplayRow);
 8871            let below_edit = Some(edit_end.row() + 1);
 8872            let above_cursor =
 8873                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8874            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8875
 8876            // Place the edit popover adjacent to the edit if there is a location
 8877            // available that is onscreen and does not obscure the cursor. Otherwise,
 8878            // place it adjacent to the cursor.
 8879            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8880                .into_iter()
 8881                .flatten()
 8882                .find(|&start_row| {
 8883                    let end_row = start_row + line_count as u32;
 8884                    visible_row_range.contains(&start_row)
 8885                        && visible_row_range.contains(&end_row)
 8886                        && cursor_row.map_or(true, |cursor_row| {
 8887                            !((start_row..end_row).contains(&cursor_row))
 8888                        })
 8889                })?;
 8890
 8891            content_origin
 8892                + point(
 8893                    -scroll_pixel_position.x,
 8894                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8895                )
 8896        };
 8897
 8898        origin.x -= BORDER_WIDTH;
 8899
 8900        window.defer_draw(element, origin, 1);
 8901
 8902        // Do not return an element, since it will already be drawn due to defer_draw.
 8903        None
 8904    }
 8905
 8906    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8907        px(30.)
 8908    }
 8909
 8910    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8911        if self.read_only(cx) {
 8912            cx.theme().players().read_only()
 8913        } else {
 8914            self.style.as_ref().unwrap().local_player
 8915        }
 8916    }
 8917
 8918    fn render_edit_prediction_accept_keybind(
 8919        &self,
 8920        window: &mut Window,
 8921        cx: &App,
 8922    ) -> Option<AnyElement> {
 8923        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8924        let accept_keystroke = accept_binding.keystroke()?;
 8925
 8926        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8927
 8928        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8929            Color::Accent
 8930        } else {
 8931            Color::Muted
 8932        };
 8933
 8934        h_flex()
 8935            .px_0p5()
 8936            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8937            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8938            .text_size(TextSize::XSmall.rems(cx))
 8939            .child(h_flex().children(ui::render_modifiers(
 8940                &accept_keystroke.modifiers,
 8941                PlatformStyle::platform(),
 8942                Some(modifiers_color),
 8943                Some(IconSize::XSmall.rems().into()),
 8944                true,
 8945            )))
 8946            .when(is_platform_style_mac, |parent| {
 8947                parent.child(accept_keystroke.key.clone())
 8948            })
 8949            .when(!is_platform_style_mac, |parent| {
 8950                parent.child(
 8951                    Key::new(
 8952                        util::capitalize(&accept_keystroke.key),
 8953                        Some(Color::Default),
 8954                    )
 8955                    .size(Some(IconSize::XSmall.rems().into())),
 8956                )
 8957            })
 8958            .into_any()
 8959            .into()
 8960    }
 8961
 8962    fn render_edit_prediction_line_popover(
 8963        &self,
 8964        label: impl Into<SharedString>,
 8965        icon: Option<IconName>,
 8966        window: &mut Window,
 8967        cx: &App,
 8968    ) -> Option<Stateful<Div>> {
 8969        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8970
 8971        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8972        let has_keybind = keybind.is_some();
 8973
 8974        let result = h_flex()
 8975            .id("ep-line-popover")
 8976            .py_0p5()
 8977            .pl_1()
 8978            .pr(padding_right)
 8979            .gap_1()
 8980            .rounded_md()
 8981            .border_1()
 8982            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8983            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8984            .shadow_xs()
 8985            .when(!has_keybind, |el| {
 8986                let status_colors = cx.theme().status();
 8987
 8988                el.bg(status_colors.error_background)
 8989                    .border_color(status_colors.error.opacity(0.6))
 8990                    .pl_2()
 8991                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8992                    .cursor_default()
 8993                    .hoverable_tooltip(move |_window, cx| {
 8994                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8995                    })
 8996            })
 8997            .children(keybind)
 8998            .child(
 8999                Label::new(label)
 9000                    .size(LabelSize::Small)
 9001                    .when(!has_keybind, |el| {
 9002                        el.color(cx.theme().status().error.into()).strikethrough()
 9003                    }),
 9004            )
 9005            .when(!has_keybind, |el| {
 9006                el.child(
 9007                    h_flex().ml_1().child(
 9008                        Icon::new(IconName::Info)
 9009                            .size(IconSize::Small)
 9010                            .color(cx.theme().status().error.into()),
 9011                    ),
 9012                )
 9013            })
 9014            .when_some(icon, |element, icon| {
 9015                element.child(
 9016                    div()
 9017                        .mt(px(1.5))
 9018                        .child(Icon::new(icon).size(IconSize::Small)),
 9019                )
 9020            });
 9021
 9022        Some(result)
 9023    }
 9024
 9025    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9026        let accent_color = cx.theme().colors().text_accent;
 9027        let editor_bg_color = cx.theme().colors().editor_background;
 9028        editor_bg_color.blend(accent_color.opacity(0.1))
 9029    }
 9030
 9031    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9032        let accent_color = cx.theme().colors().text_accent;
 9033        let editor_bg_color = cx.theme().colors().editor_background;
 9034        editor_bg_color.blend(accent_color.opacity(0.6))
 9035    }
 9036
 9037    fn render_edit_prediction_cursor_popover(
 9038        &self,
 9039        min_width: Pixels,
 9040        max_width: Pixels,
 9041        cursor_point: Point,
 9042        style: &EditorStyle,
 9043        accept_keystroke: Option<&gpui::Keystroke>,
 9044        _window: &Window,
 9045        cx: &mut Context<Editor>,
 9046    ) -> Option<AnyElement> {
 9047        let provider = self.edit_prediction_provider.as_ref()?;
 9048
 9049        if provider.provider.needs_terms_acceptance(cx) {
 9050            return Some(
 9051                h_flex()
 9052                    .min_w(min_width)
 9053                    .flex_1()
 9054                    .px_2()
 9055                    .py_1()
 9056                    .gap_3()
 9057                    .elevation_2(cx)
 9058                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9059                    .id("accept-terms")
 9060                    .cursor_pointer()
 9061                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9062                    .on_click(cx.listener(|this, _event, window, cx| {
 9063                        cx.stop_propagation();
 9064                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9065                        window.dispatch_action(
 9066                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9067                            cx,
 9068                        );
 9069                    }))
 9070                    .child(
 9071                        h_flex()
 9072                            .flex_1()
 9073                            .gap_2()
 9074                            .child(Icon::new(IconName::ZedPredict))
 9075                            .child(Label::new("Accept Terms of Service"))
 9076                            .child(div().w_full())
 9077                            .child(
 9078                                Icon::new(IconName::ArrowUpRight)
 9079                                    .color(Color::Muted)
 9080                                    .size(IconSize::Small),
 9081                            )
 9082                            .into_any_element(),
 9083                    )
 9084                    .into_any(),
 9085            );
 9086        }
 9087
 9088        let is_refreshing = provider.provider.is_refreshing(cx);
 9089
 9090        fn pending_completion_container() -> Div {
 9091            h_flex()
 9092                .h_full()
 9093                .flex_1()
 9094                .gap_2()
 9095                .child(Icon::new(IconName::ZedPredict))
 9096        }
 9097
 9098        let completion = match &self.active_inline_completion {
 9099            Some(prediction) => {
 9100                if !self.has_visible_completions_menu() {
 9101                    const RADIUS: Pixels = px(6.);
 9102                    const BORDER_WIDTH: Pixels = px(1.);
 9103
 9104                    return Some(
 9105                        h_flex()
 9106                            .elevation_2(cx)
 9107                            .border(BORDER_WIDTH)
 9108                            .border_color(cx.theme().colors().border)
 9109                            .when(accept_keystroke.is_none(), |el| {
 9110                                el.border_color(cx.theme().status().error)
 9111                            })
 9112                            .rounded(RADIUS)
 9113                            .rounded_tl(px(0.))
 9114                            .overflow_hidden()
 9115                            .child(div().px_1p5().child(match &prediction.completion {
 9116                                InlineCompletion::Move { target, snapshot } => {
 9117                                    use text::ToPoint as _;
 9118                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9119                                    {
 9120                                        Icon::new(IconName::ZedPredictDown)
 9121                                    } else {
 9122                                        Icon::new(IconName::ZedPredictUp)
 9123                                    }
 9124                                }
 9125                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9126                            }))
 9127                            .child(
 9128                                h_flex()
 9129                                    .gap_1()
 9130                                    .py_1()
 9131                                    .px_2()
 9132                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9133                                    .border_l_1()
 9134                                    .border_color(cx.theme().colors().border)
 9135                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9136                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9137                                        el.child(
 9138                                            Label::new("Hold")
 9139                                                .size(LabelSize::Small)
 9140                                                .when(accept_keystroke.is_none(), |el| {
 9141                                                    el.strikethrough()
 9142                                                })
 9143                                                .line_height_style(LineHeightStyle::UiLabel),
 9144                                        )
 9145                                    })
 9146                                    .id("edit_prediction_cursor_popover_keybind")
 9147                                    .when(accept_keystroke.is_none(), |el| {
 9148                                        let status_colors = cx.theme().status();
 9149
 9150                                        el.bg(status_colors.error_background)
 9151                                            .border_color(status_colors.error.opacity(0.6))
 9152                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9153                                            .cursor_default()
 9154                                            .hoverable_tooltip(move |_window, cx| {
 9155                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9156                                                    .into()
 9157                                            })
 9158                                    })
 9159                                    .when_some(
 9160                                        accept_keystroke.as_ref(),
 9161                                        |el, accept_keystroke| {
 9162                                            el.child(h_flex().children(ui::render_modifiers(
 9163                                                &accept_keystroke.modifiers,
 9164                                                PlatformStyle::platform(),
 9165                                                Some(Color::Default),
 9166                                                Some(IconSize::XSmall.rems().into()),
 9167                                                false,
 9168                                            )))
 9169                                        },
 9170                                    ),
 9171                            )
 9172                            .into_any(),
 9173                    );
 9174                }
 9175
 9176                self.render_edit_prediction_cursor_popover_preview(
 9177                    prediction,
 9178                    cursor_point,
 9179                    style,
 9180                    cx,
 9181                )?
 9182            }
 9183
 9184            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9185                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9186                    stale_completion,
 9187                    cursor_point,
 9188                    style,
 9189                    cx,
 9190                )?,
 9191
 9192                None => {
 9193                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9194                }
 9195            },
 9196
 9197            None => pending_completion_container().child(Label::new("No Prediction")),
 9198        };
 9199
 9200        let completion = if is_refreshing {
 9201            completion
 9202                .with_animation(
 9203                    "loading-completion",
 9204                    Animation::new(Duration::from_secs(2))
 9205                        .repeat()
 9206                        .with_easing(pulsating_between(0.4, 0.8)),
 9207                    |label, delta| label.opacity(delta),
 9208                )
 9209                .into_any_element()
 9210        } else {
 9211            completion.into_any_element()
 9212        };
 9213
 9214        let has_completion = self.active_inline_completion.is_some();
 9215
 9216        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9217        Some(
 9218            h_flex()
 9219                .min_w(min_width)
 9220                .max_w(max_width)
 9221                .flex_1()
 9222                .elevation_2(cx)
 9223                .border_color(cx.theme().colors().border)
 9224                .child(
 9225                    div()
 9226                        .flex_1()
 9227                        .py_1()
 9228                        .px_2()
 9229                        .overflow_hidden()
 9230                        .child(completion),
 9231                )
 9232                .when_some(accept_keystroke, |el, accept_keystroke| {
 9233                    if !accept_keystroke.modifiers.modified() {
 9234                        return el;
 9235                    }
 9236
 9237                    el.child(
 9238                        h_flex()
 9239                            .h_full()
 9240                            .border_l_1()
 9241                            .rounded_r_lg()
 9242                            .border_color(cx.theme().colors().border)
 9243                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9244                            .gap_1()
 9245                            .py_1()
 9246                            .px_2()
 9247                            .child(
 9248                                h_flex()
 9249                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9250                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9251                                    .child(h_flex().children(ui::render_modifiers(
 9252                                        &accept_keystroke.modifiers,
 9253                                        PlatformStyle::platform(),
 9254                                        Some(if !has_completion {
 9255                                            Color::Muted
 9256                                        } else {
 9257                                            Color::Default
 9258                                        }),
 9259                                        None,
 9260                                        false,
 9261                                    ))),
 9262                            )
 9263                            .child(Label::new("Preview").into_any_element())
 9264                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9265                    )
 9266                })
 9267                .into_any(),
 9268        )
 9269    }
 9270
 9271    fn render_edit_prediction_cursor_popover_preview(
 9272        &self,
 9273        completion: &InlineCompletionState,
 9274        cursor_point: Point,
 9275        style: &EditorStyle,
 9276        cx: &mut Context<Editor>,
 9277    ) -> Option<Div> {
 9278        use text::ToPoint as _;
 9279
 9280        fn render_relative_row_jump(
 9281            prefix: impl Into<String>,
 9282            current_row: u32,
 9283            target_row: u32,
 9284        ) -> Div {
 9285            let (row_diff, arrow) = if target_row < current_row {
 9286                (current_row - target_row, IconName::ArrowUp)
 9287            } else {
 9288                (target_row - current_row, IconName::ArrowDown)
 9289            };
 9290
 9291            h_flex()
 9292                .child(
 9293                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9294                        .color(Color::Muted)
 9295                        .size(LabelSize::Small),
 9296                )
 9297                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9298        }
 9299
 9300        match &completion.completion {
 9301            InlineCompletion::Move {
 9302                target, snapshot, ..
 9303            } => Some(
 9304                h_flex()
 9305                    .px_2()
 9306                    .gap_2()
 9307                    .flex_1()
 9308                    .child(
 9309                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9310                            Icon::new(IconName::ZedPredictDown)
 9311                        } else {
 9312                            Icon::new(IconName::ZedPredictUp)
 9313                        },
 9314                    )
 9315                    .child(Label::new("Jump to Edit")),
 9316            ),
 9317
 9318            InlineCompletion::Edit {
 9319                edits,
 9320                edit_preview,
 9321                snapshot,
 9322                display_mode: _,
 9323            } => {
 9324                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9325
 9326                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9327                    &snapshot,
 9328                    &edits,
 9329                    edit_preview.as_ref()?,
 9330                    true,
 9331                    cx,
 9332                )
 9333                .first_line_preview();
 9334
 9335                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9336                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9337
 9338                let preview = h_flex()
 9339                    .gap_1()
 9340                    .min_w_16()
 9341                    .child(styled_text)
 9342                    .when(has_more_lines, |parent| parent.child(""));
 9343
 9344                let left = if first_edit_row != cursor_point.row {
 9345                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9346                        .into_any_element()
 9347                } else {
 9348                    Icon::new(IconName::ZedPredict).into_any_element()
 9349                };
 9350
 9351                Some(
 9352                    h_flex()
 9353                        .h_full()
 9354                        .flex_1()
 9355                        .gap_2()
 9356                        .pr_1()
 9357                        .overflow_x_hidden()
 9358                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9359                        .child(left)
 9360                        .child(preview),
 9361                )
 9362            }
 9363        }
 9364    }
 9365
 9366    pub fn render_context_menu(
 9367        &self,
 9368        style: &EditorStyle,
 9369        max_height_in_lines: u32,
 9370        window: &mut Window,
 9371        cx: &mut Context<Editor>,
 9372    ) -> Option<AnyElement> {
 9373        let menu = self.context_menu.borrow();
 9374        let menu = menu.as_ref()?;
 9375        if !menu.visible() {
 9376            return None;
 9377        };
 9378        Some(menu.render(style, max_height_in_lines, window, cx))
 9379    }
 9380
 9381    fn render_context_menu_aside(
 9382        &mut self,
 9383        max_size: Size<Pixels>,
 9384        window: &mut Window,
 9385        cx: &mut Context<Editor>,
 9386    ) -> Option<AnyElement> {
 9387        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9388            if menu.visible() {
 9389                menu.render_aside(max_size, window, cx)
 9390            } else {
 9391                None
 9392            }
 9393        })
 9394    }
 9395
 9396    fn hide_context_menu(
 9397        &mut self,
 9398        window: &mut Window,
 9399        cx: &mut Context<Self>,
 9400    ) -> Option<CodeContextMenu> {
 9401        cx.notify();
 9402        self.completion_tasks.clear();
 9403        let context_menu = self.context_menu.borrow_mut().take();
 9404        self.stale_inline_completion_in_menu.take();
 9405        self.update_visible_inline_completion(window, cx);
 9406        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9407            if let Some(completion_provider) = &self.completion_provider {
 9408                completion_provider.selection_changed(None, window, cx);
 9409            }
 9410        }
 9411        context_menu
 9412    }
 9413
 9414    fn show_snippet_choices(
 9415        &mut self,
 9416        choices: &Vec<String>,
 9417        selection: Range<Anchor>,
 9418        cx: &mut Context<Self>,
 9419    ) {
 9420        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9421            (Some(a), Some(b)) if a == b => a,
 9422            _ => {
 9423                log::error!("expected anchor range to have matching buffer IDs");
 9424                return;
 9425            }
 9426        };
 9427        let multi_buffer = self.buffer().read(cx);
 9428        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9429            return;
 9430        };
 9431
 9432        let id = post_inc(&mut self.next_completion_id);
 9433        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9434        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9435            CompletionsMenu::new_snippet_choices(
 9436                id,
 9437                true,
 9438                choices,
 9439                selection,
 9440                buffer,
 9441                snippet_sort_order,
 9442            ),
 9443        ));
 9444    }
 9445
 9446    pub fn insert_snippet(
 9447        &mut self,
 9448        insertion_ranges: &[Range<usize>],
 9449        snippet: Snippet,
 9450        window: &mut Window,
 9451        cx: &mut Context<Self>,
 9452    ) -> Result<()> {
 9453        struct Tabstop<T> {
 9454            is_end_tabstop: bool,
 9455            ranges: Vec<Range<T>>,
 9456            choices: Option<Vec<String>>,
 9457        }
 9458
 9459        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9460            let snippet_text: Arc<str> = snippet.text.clone().into();
 9461            let edits = insertion_ranges
 9462                .iter()
 9463                .cloned()
 9464                .map(|range| (range, snippet_text.clone()));
 9465            let autoindent_mode = AutoindentMode::Block {
 9466                original_indent_columns: Vec::new(),
 9467            };
 9468            buffer.edit(edits, Some(autoindent_mode), cx);
 9469
 9470            let snapshot = &*buffer.read(cx);
 9471            let snippet = &snippet;
 9472            snippet
 9473                .tabstops
 9474                .iter()
 9475                .map(|tabstop| {
 9476                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9477                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9478                    });
 9479                    let mut tabstop_ranges = tabstop
 9480                        .ranges
 9481                        .iter()
 9482                        .flat_map(|tabstop_range| {
 9483                            let mut delta = 0_isize;
 9484                            insertion_ranges.iter().map(move |insertion_range| {
 9485                                let insertion_start = insertion_range.start as isize + delta;
 9486                                delta +=
 9487                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9488
 9489                                let start = ((insertion_start + tabstop_range.start) as usize)
 9490                                    .min(snapshot.len());
 9491                                let end = ((insertion_start + tabstop_range.end) as usize)
 9492                                    .min(snapshot.len());
 9493                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9494                            })
 9495                        })
 9496                        .collect::<Vec<_>>();
 9497                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9498
 9499                    Tabstop {
 9500                        is_end_tabstop,
 9501                        ranges: tabstop_ranges,
 9502                        choices: tabstop.choices.clone(),
 9503                    }
 9504                })
 9505                .collect::<Vec<_>>()
 9506        });
 9507        if let Some(tabstop) = tabstops.first() {
 9508            self.change_selections(Default::default(), window, cx, |s| {
 9509                // Reverse order so that the first range is the newest created selection.
 9510                // Completions will use it and autoscroll will prioritize it.
 9511                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9512            });
 9513
 9514            if let Some(choices) = &tabstop.choices {
 9515                if let Some(selection) = tabstop.ranges.first() {
 9516                    self.show_snippet_choices(choices, selection.clone(), cx)
 9517                }
 9518            }
 9519
 9520            // If we're already at the last tabstop and it's at the end of the snippet,
 9521            // we're done, we don't need to keep the state around.
 9522            if !tabstop.is_end_tabstop {
 9523                let choices = tabstops
 9524                    .iter()
 9525                    .map(|tabstop| tabstop.choices.clone())
 9526                    .collect();
 9527
 9528                let ranges = tabstops
 9529                    .into_iter()
 9530                    .map(|tabstop| tabstop.ranges)
 9531                    .collect::<Vec<_>>();
 9532
 9533                self.snippet_stack.push(SnippetState {
 9534                    active_index: 0,
 9535                    ranges,
 9536                    choices,
 9537                });
 9538            }
 9539
 9540            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9541            if self.autoclose_regions.is_empty() {
 9542                let snapshot = self.buffer.read(cx).snapshot(cx);
 9543                for selection in &mut self.selections.all::<Point>(cx) {
 9544                    let selection_head = selection.head();
 9545                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9546                        continue;
 9547                    };
 9548
 9549                    let mut bracket_pair = None;
 9550                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9551                    let prev_chars = snapshot
 9552                        .reversed_chars_at(selection_head)
 9553                        .collect::<String>();
 9554                    for (pair, enabled) in scope.brackets() {
 9555                        if enabled
 9556                            && pair.close
 9557                            && prev_chars.starts_with(pair.start.as_str())
 9558                            && next_chars.starts_with(pair.end.as_str())
 9559                        {
 9560                            bracket_pair = Some(pair.clone());
 9561                            break;
 9562                        }
 9563                    }
 9564                    if let Some(pair) = bracket_pair {
 9565                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9566                        let autoclose_enabled =
 9567                            self.use_autoclose && snapshot_settings.use_autoclose;
 9568                        if autoclose_enabled {
 9569                            let start = snapshot.anchor_after(selection_head);
 9570                            let end = snapshot.anchor_after(selection_head);
 9571                            self.autoclose_regions.push(AutocloseRegion {
 9572                                selection_id: selection.id,
 9573                                range: start..end,
 9574                                pair,
 9575                            });
 9576                        }
 9577                    }
 9578                }
 9579            }
 9580        }
 9581        Ok(())
 9582    }
 9583
 9584    pub fn move_to_next_snippet_tabstop(
 9585        &mut self,
 9586        window: &mut Window,
 9587        cx: &mut Context<Self>,
 9588    ) -> bool {
 9589        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9590    }
 9591
 9592    pub fn move_to_prev_snippet_tabstop(
 9593        &mut self,
 9594        window: &mut Window,
 9595        cx: &mut Context<Self>,
 9596    ) -> bool {
 9597        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9598    }
 9599
 9600    pub fn move_to_snippet_tabstop(
 9601        &mut self,
 9602        bias: Bias,
 9603        window: &mut Window,
 9604        cx: &mut Context<Self>,
 9605    ) -> bool {
 9606        if let Some(mut snippet) = self.snippet_stack.pop() {
 9607            match bias {
 9608                Bias::Left => {
 9609                    if snippet.active_index > 0 {
 9610                        snippet.active_index -= 1;
 9611                    } else {
 9612                        self.snippet_stack.push(snippet);
 9613                        return false;
 9614                    }
 9615                }
 9616                Bias::Right => {
 9617                    if snippet.active_index + 1 < snippet.ranges.len() {
 9618                        snippet.active_index += 1;
 9619                    } else {
 9620                        self.snippet_stack.push(snippet);
 9621                        return false;
 9622                    }
 9623                }
 9624            }
 9625            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9626                self.change_selections(Default::default(), window, cx, |s| {
 9627                    // Reverse order so that the first range is the newest created selection.
 9628                    // Completions will use it and autoscroll will prioritize it.
 9629                    s.select_ranges(current_ranges.iter().rev().cloned())
 9630                });
 9631
 9632                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9633                    if let Some(selection) = current_ranges.first() {
 9634                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9635                    }
 9636                }
 9637
 9638                // If snippet state is not at the last tabstop, push it back on the stack
 9639                if snippet.active_index + 1 < snippet.ranges.len() {
 9640                    self.snippet_stack.push(snippet);
 9641                }
 9642                return true;
 9643            }
 9644        }
 9645
 9646        false
 9647    }
 9648
 9649    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9650        self.transact(window, cx, |this, window, cx| {
 9651            this.select_all(&SelectAll, window, cx);
 9652            this.insert("", window, cx);
 9653        });
 9654    }
 9655
 9656    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9658        self.transact(window, cx, |this, window, cx| {
 9659            this.select_autoclose_pair(window, cx);
 9660            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9661            if !this.linked_edit_ranges.is_empty() {
 9662                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9663                let snapshot = this.buffer.read(cx).snapshot(cx);
 9664
 9665                for selection in selections.iter() {
 9666                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9667                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9668                    if selection_start.buffer_id != selection_end.buffer_id {
 9669                        continue;
 9670                    }
 9671                    if let Some(ranges) =
 9672                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9673                    {
 9674                        for (buffer, entries) in ranges {
 9675                            linked_ranges.entry(buffer).or_default().extend(entries);
 9676                        }
 9677                    }
 9678                }
 9679            }
 9680
 9681            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9682            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9683            for selection in &mut selections {
 9684                if selection.is_empty() {
 9685                    let old_head = selection.head();
 9686                    let mut new_head =
 9687                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9688                            .to_point(&display_map);
 9689                    if let Some((buffer, line_buffer_range)) = display_map
 9690                        .buffer_snapshot
 9691                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9692                    {
 9693                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9694                        let indent_len = match indent_size.kind {
 9695                            IndentKind::Space => {
 9696                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9697                            }
 9698                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9699                        };
 9700                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9701                            let indent_len = indent_len.get();
 9702                            new_head = cmp::min(
 9703                                new_head,
 9704                                MultiBufferPoint::new(
 9705                                    old_head.row,
 9706                                    ((old_head.column - 1) / indent_len) * indent_len,
 9707                                ),
 9708                            );
 9709                        }
 9710                    }
 9711
 9712                    selection.set_head(new_head, SelectionGoal::None);
 9713                }
 9714            }
 9715
 9716            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9717            this.insert("", window, cx);
 9718            let empty_str: Arc<str> = Arc::from("");
 9719            for (buffer, edits) in linked_ranges {
 9720                let snapshot = buffer.read(cx).snapshot();
 9721                use text::ToPoint as TP;
 9722
 9723                let edits = edits
 9724                    .into_iter()
 9725                    .map(|range| {
 9726                        let end_point = TP::to_point(&range.end, &snapshot);
 9727                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9728
 9729                        if end_point == start_point {
 9730                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9731                                .saturating_sub(1);
 9732                            start_point =
 9733                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9734                        };
 9735
 9736                        (start_point..end_point, empty_str.clone())
 9737                    })
 9738                    .sorted_by_key(|(range, _)| range.start)
 9739                    .collect::<Vec<_>>();
 9740                buffer.update(cx, |this, cx| {
 9741                    this.edit(edits, None, cx);
 9742                })
 9743            }
 9744            this.refresh_inline_completion(true, false, window, cx);
 9745            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9746        });
 9747    }
 9748
 9749    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9751        self.transact(window, cx, |this, window, cx| {
 9752            this.change_selections(Default::default(), window, cx, |s| {
 9753                s.move_with(|map, selection| {
 9754                    if selection.is_empty() {
 9755                        let cursor = movement::right(map, selection.head());
 9756                        selection.end = cursor;
 9757                        selection.reversed = true;
 9758                        selection.goal = SelectionGoal::None;
 9759                    }
 9760                })
 9761            });
 9762            this.insert("", window, cx);
 9763            this.refresh_inline_completion(true, false, window, cx);
 9764        });
 9765    }
 9766
 9767    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9768        if self.mode.is_single_line() {
 9769            cx.propagate();
 9770            return;
 9771        }
 9772
 9773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9774        if self.move_to_prev_snippet_tabstop(window, cx) {
 9775            return;
 9776        }
 9777        self.outdent(&Outdent, window, cx);
 9778    }
 9779
 9780    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9781        if self.mode.is_single_line() {
 9782            cx.propagate();
 9783            return;
 9784        }
 9785
 9786        if self.move_to_next_snippet_tabstop(window, cx) {
 9787            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9788            return;
 9789        }
 9790        if self.read_only(cx) {
 9791            return;
 9792        }
 9793        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9794        let mut selections = self.selections.all_adjusted(cx);
 9795        let buffer = self.buffer.read(cx);
 9796        let snapshot = buffer.snapshot(cx);
 9797        let rows_iter = selections.iter().map(|s| s.head().row);
 9798        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9799
 9800        let has_some_cursor_in_whitespace = selections
 9801            .iter()
 9802            .filter(|selection| selection.is_empty())
 9803            .any(|selection| {
 9804                let cursor = selection.head();
 9805                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9806                cursor.column < current_indent.len
 9807            });
 9808
 9809        let mut edits = Vec::new();
 9810        let mut prev_edited_row = 0;
 9811        let mut row_delta = 0;
 9812        for selection in &mut selections {
 9813            if selection.start.row != prev_edited_row {
 9814                row_delta = 0;
 9815            }
 9816            prev_edited_row = selection.end.row;
 9817
 9818            // If the selection is non-empty, then increase the indentation of the selected lines.
 9819            if !selection.is_empty() {
 9820                row_delta =
 9821                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9822                continue;
 9823            }
 9824
 9825            let cursor = selection.head();
 9826            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9827            if let Some(suggested_indent) =
 9828                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9829            {
 9830                // Don't do anything if already at suggested indent
 9831                // and there is any other cursor which is not
 9832                if has_some_cursor_in_whitespace
 9833                    && cursor.column == current_indent.len
 9834                    && current_indent.len == suggested_indent.len
 9835                {
 9836                    continue;
 9837                }
 9838
 9839                // Adjust line and move cursor to suggested indent
 9840                // if cursor is not at suggested indent
 9841                if cursor.column < suggested_indent.len
 9842                    && cursor.column <= current_indent.len
 9843                    && current_indent.len <= suggested_indent.len
 9844                {
 9845                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9846                    selection.end = selection.start;
 9847                    if row_delta == 0 {
 9848                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9849                            cursor.row,
 9850                            current_indent,
 9851                            suggested_indent,
 9852                        ));
 9853                        row_delta = suggested_indent.len - current_indent.len;
 9854                    }
 9855                    continue;
 9856                }
 9857
 9858                // If current indent is more than suggested indent
 9859                // only move cursor to current indent and skip indent
 9860                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9861                    selection.start = Point::new(cursor.row, current_indent.len);
 9862                    selection.end = selection.start;
 9863                    continue;
 9864                }
 9865            }
 9866
 9867            // Otherwise, insert a hard or soft tab.
 9868            let settings = buffer.language_settings_at(cursor, cx);
 9869            let tab_size = if settings.hard_tabs {
 9870                IndentSize::tab()
 9871            } else {
 9872                let tab_size = settings.tab_size.get();
 9873                let indent_remainder = snapshot
 9874                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9875                    .flat_map(str::chars)
 9876                    .fold(row_delta % tab_size, |counter: u32, c| {
 9877                        if c == '\t' {
 9878                            0
 9879                        } else {
 9880                            (counter + 1) % tab_size
 9881                        }
 9882                    });
 9883
 9884                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9885                IndentSize::spaces(chars_to_next_tab_stop)
 9886            };
 9887            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9888            selection.end = selection.start;
 9889            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9890            row_delta += tab_size.len;
 9891        }
 9892
 9893        self.transact(window, cx, |this, window, cx| {
 9894            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9895            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9896            this.refresh_inline_completion(true, false, window, cx);
 9897        });
 9898    }
 9899
 9900    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9901        if self.read_only(cx) {
 9902            return;
 9903        }
 9904        if self.mode.is_single_line() {
 9905            cx.propagate();
 9906            return;
 9907        }
 9908
 9909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9910        let mut selections = self.selections.all::<Point>(cx);
 9911        let mut prev_edited_row = 0;
 9912        let mut row_delta = 0;
 9913        let mut edits = Vec::new();
 9914        let buffer = self.buffer.read(cx);
 9915        let snapshot = buffer.snapshot(cx);
 9916        for selection in &mut selections {
 9917            if selection.start.row != prev_edited_row {
 9918                row_delta = 0;
 9919            }
 9920            prev_edited_row = selection.end.row;
 9921
 9922            row_delta =
 9923                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9924        }
 9925
 9926        self.transact(window, cx, |this, window, cx| {
 9927            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9928            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9929        });
 9930    }
 9931
 9932    fn indent_selection(
 9933        buffer: &MultiBuffer,
 9934        snapshot: &MultiBufferSnapshot,
 9935        selection: &mut Selection<Point>,
 9936        edits: &mut Vec<(Range<Point>, String)>,
 9937        delta_for_start_row: u32,
 9938        cx: &App,
 9939    ) -> u32 {
 9940        let settings = buffer.language_settings_at(selection.start, cx);
 9941        let tab_size = settings.tab_size.get();
 9942        let indent_kind = if settings.hard_tabs {
 9943            IndentKind::Tab
 9944        } else {
 9945            IndentKind::Space
 9946        };
 9947        let mut start_row = selection.start.row;
 9948        let mut end_row = selection.end.row + 1;
 9949
 9950        // If a selection ends at the beginning of a line, don't indent
 9951        // that last line.
 9952        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9953            end_row -= 1;
 9954        }
 9955
 9956        // Avoid re-indenting a row that has already been indented by a
 9957        // previous selection, but still update this selection's column
 9958        // to reflect that indentation.
 9959        if delta_for_start_row > 0 {
 9960            start_row += 1;
 9961            selection.start.column += delta_for_start_row;
 9962            if selection.end.row == selection.start.row {
 9963                selection.end.column += delta_for_start_row;
 9964            }
 9965        }
 9966
 9967        let mut delta_for_end_row = 0;
 9968        let has_multiple_rows = start_row + 1 != end_row;
 9969        for row in start_row..end_row {
 9970            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9971            let indent_delta = match (current_indent.kind, indent_kind) {
 9972                (IndentKind::Space, IndentKind::Space) => {
 9973                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9974                    IndentSize::spaces(columns_to_next_tab_stop)
 9975                }
 9976                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9977                (_, IndentKind::Tab) => IndentSize::tab(),
 9978            };
 9979
 9980            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9981                0
 9982            } else {
 9983                selection.start.column
 9984            };
 9985            let row_start = Point::new(row, start);
 9986            edits.push((
 9987                row_start..row_start,
 9988                indent_delta.chars().collect::<String>(),
 9989            ));
 9990
 9991            // Update this selection's endpoints to reflect the indentation.
 9992            if row == selection.start.row {
 9993                selection.start.column += indent_delta.len;
 9994            }
 9995            if row == selection.end.row {
 9996                selection.end.column += indent_delta.len;
 9997                delta_for_end_row = indent_delta.len;
 9998            }
 9999        }
10000
10001        if selection.start.row == selection.end.row {
10002            delta_for_start_row + delta_for_end_row
10003        } else {
10004            delta_for_end_row
10005        }
10006    }
10007
10008    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10009        if self.read_only(cx) {
10010            return;
10011        }
10012        if self.mode.is_single_line() {
10013            cx.propagate();
10014            return;
10015        }
10016
10017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10018        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10019        let selections = self.selections.all::<Point>(cx);
10020        let mut deletion_ranges = Vec::new();
10021        let mut last_outdent = None;
10022        {
10023            let buffer = self.buffer.read(cx);
10024            let snapshot = buffer.snapshot(cx);
10025            for selection in &selections {
10026                let settings = buffer.language_settings_at(selection.start, cx);
10027                let tab_size = settings.tab_size.get();
10028                let mut rows = selection.spanned_rows(false, &display_map);
10029
10030                // Avoid re-outdenting a row that has already been outdented by a
10031                // previous selection.
10032                if let Some(last_row) = last_outdent {
10033                    if last_row == rows.start {
10034                        rows.start = rows.start.next_row();
10035                    }
10036                }
10037                let has_multiple_rows = rows.len() > 1;
10038                for row in rows.iter_rows() {
10039                    let indent_size = snapshot.indent_size_for_line(row);
10040                    if indent_size.len > 0 {
10041                        let deletion_len = match indent_size.kind {
10042                            IndentKind::Space => {
10043                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10044                                if columns_to_prev_tab_stop == 0 {
10045                                    tab_size
10046                                } else {
10047                                    columns_to_prev_tab_stop
10048                                }
10049                            }
10050                            IndentKind::Tab => 1,
10051                        };
10052                        let start = if has_multiple_rows
10053                            || deletion_len > selection.start.column
10054                            || indent_size.len < selection.start.column
10055                        {
10056                            0
10057                        } else {
10058                            selection.start.column - deletion_len
10059                        };
10060                        deletion_ranges.push(
10061                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10062                        );
10063                        last_outdent = Some(row);
10064                    }
10065                }
10066            }
10067        }
10068
10069        self.transact(window, cx, |this, window, cx| {
10070            this.buffer.update(cx, |buffer, cx| {
10071                let empty_str: Arc<str> = Arc::default();
10072                buffer.edit(
10073                    deletion_ranges
10074                        .into_iter()
10075                        .map(|range| (range, empty_str.clone())),
10076                    None,
10077                    cx,
10078                );
10079            });
10080            let selections = this.selections.all::<usize>(cx);
10081            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10082        });
10083    }
10084
10085    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10086        if self.read_only(cx) {
10087            return;
10088        }
10089        if self.mode.is_single_line() {
10090            cx.propagate();
10091            return;
10092        }
10093
10094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10095        let selections = self
10096            .selections
10097            .all::<usize>(cx)
10098            .into_iter()
10099            .map(|s| s.range());
10100
10101        self.transact(window, cx, |this, window, cx| {
10102            this.buffer.update(cx, |buffer, cx| {
10103                buffer.autoindent_ranges(selections, cx);
10104            });
10105            let selections = this.selections.all::<usize>(cx);
10106            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10107        });
10108    }
10109
10110    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10112        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10113        let selections = self.selections.all::<Point>(cx);
10114
10115        let mut new_cursors = Vec::new();
10116        let mut edit_ranges = Vec::new();
10117        let mut selections = selections.iter().peekable();
10118        while let Some(selection) = selections.next() {
10119            let mut rows = selection.spanned_rows(false, &display_map);
10120            let goal_display_column = selection.head().to_display_point(&display_map).column();
10121
10122            // Accumulate contiguous regions of rows that we want to delete.
10123            while let Some(next_selection) = selections.peek() {
10124                let next_rows = next_selection.spanned_rows(false, &display_map);
10125                if next_rows.start <= rows.end {
10126                    rows.end = next_rows.end;
10127                    selections.next().unwrap();
10128                } else {
10129                    break;
10130                }
10131            }
10132
10133            let buffer = &display_map.buffer_snapshot;
10134            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10135            let edit_end;
10136            let cursor_buffer_row;
10137            if buffer.max_point().row >= rows.end.0 {
10138                // If there's a line after the range, delete the \n from the end of the row range
10139                // and position the cursor on the next line.
10140                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10141                cursor_buffer_row = rows.end;
10142            } else {
10143                // If there isn't a line after the range, delete the \n from the line before the
10144                // start of the row range and position the cursor there.
10145                edit_start = edit_start.saturating_sub(1);
10146                edit_end = buffer.len();
10147                cursor_buffer_row = rows.start.previous_row();
10148            }
10149
10150            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10151            *cursor.column_mut() =
10152                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10153
10154            new_cursors.push((
10155                selection.id,
10156                buffer.anchor_after(cursor.to_point(&display_map)),
10157            ));
10158            edit_ranges.push(edit_start..edit_end);
10159        }
10160
10161        self.transact(window, cx, |this, window, cx| {
10162            let buffer = this.buffer.update(cx, |buffer, cx| {
10163                let empty_str: Arc<str> = Arc::default();
10164                buffer.edit(
10165                    edit_ranges
10166                        .into_iter()
10167                        .map(|range| (range, empty_str.clone())),
10168                    None,
10169                    cx,
10170                );
10171                buffer.snapshot(cx)
10172            });
10173            let new_selections = new_cursors
10174                .into_iter()
10175                .map(|(id, cursor)| {
10176                    let cursor = cursor.to_point(&buffer);
10177                    Selection {
10178                        id,
10179                        start: cursor,
10180                        end: cursor,
10181                        reversed: false,
10182                        goal: SelectionGoal::None,
10183                    }
10184                })
10185                .collect();
10186
10187            this.change_selections(Default::default(), window, cx, |s| {
10188                s.select(new_selections);
10189            });
10190        });
10191    }
10192
10193    pub fn join_lines_impl(
10194        &mut self,
10195        insert_whitespace: bool,
10196        window: &mut Window,
10197        cx: &mut Context<Self>,
10198    ) {
10199        if self.read_only(cx) {
10200            return;
10201        }
10202        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10203        for selection in self.selections.all::<Point>(cx) {
10204            let start = MultiBufferRow(selection.start.row);
10205            // Treat single line selections as if they include the next line. Otherwise this action
10206            // would do nothing for single line selections individual cursors.
10207            let end = if selection.start.row == selection.end.row {
10208                MultiBufferRow(selection.start.row + 1)
10209            } else {
10210                MultiBufferRow(selection.end.row)
10211            };
10212
10213            if let Some(last_row_range) = row_ranges.last_mut() {
10214                if start <= last_row_range.end {
10215                    last_row_range.end = end;
10216                    continue;
10217                }
10218            }
10219            row_ranges.push(start..end);
10220        }
10221
10222        let snapshot = self.buffer.read(cx).snapshot(cx);
10223        let mut cursor_positions = Vec::new();
10224        for row_range in &row_ranges {
10225            let anchor = snapshot.anchor_before(Point::new(
10226                row_range.end.previous_row().0,
10227                snapshot.line_len(row_range.end.previous_row()),
10228            ));
10229            cursor_positions.push(anchor..anchor);
10230        }
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            for row_range in row_ranges.into_iter().rev() {
10234                for row in row_range.iter_rows().rev() {
10235                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10236                    let next_line_row = row.next_row();
10237                    let indent = snapshot.indent_size_for_line(next_line_row);
10238                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10239
10240                    let replace =
10241                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10242                            " "
10243                        } else {
10244                            ""
10245                        };
10246
10247                    this.buffer.update(cx, |buffer, cx| {
10248                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10249                    });
10250                }
10251            }
10252
10253            this.change_selections(Default::default(), window, cx, |s| {
10254                s.select_anchor_ranges(cursor_positions)
10255            });
10256        });
10257    }
10258
10259    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10261        self.join_lines_impl(true, window, cx);
10262    }
10263
10264    pub fn sort_lines_case_sensitive(
10265        &mut self,
10266        _: &SortLinesCaseSensitive,
10267        window: &mut Window,
10268        cx: &mut Context<Self>,
10269    ) {
10270        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10271    }
10272
10273    pub fn sort_lines_by_length(
10274        &mut self,
10275        _: &SortLinesByLength,
10276        window: &mut Window,
10277        cx: &mut Context<Self>,
10278    ) {
10279        self.manipulate_immutable_lines(window, cx, |lines| {
10280            lines.sort_by_key(|&line| line.chars().count())
10281        })
10282    }
10283
10284    pub fn sort_lines_case_insensitive(
10285        &mut self,
10286        _: &SortLinesCaseInsensitive,
10287        window: &mut Window,
10288        cx: &mut Context<Self>,
10289    ) {
10290        self.manipulate_immutable_lines(window, cx, |lines| {
10291            lines.sort_by_key(|line| line.to_lowercase())
10292        })
10293    }
10294
10295    pub fn unique_lines_case_insensitive(
10296        &mut self,
10297        _: &UniqueLinesCaseInsensitive,
10298        window: &mut Window,
10299        cx: &mut Context<Self>,
10300    ) {
10301        self.manipulate_immutable_lines(window, cx, |lines| {
10302            let mut seen = HashSet::default();
10303            lines.retain(|line| seen.insert(line.to_lowercase()));
10304        })
10305    }
10306
10307    pub fn unique_lines_case_sensitive(
10308        &mut self,
10309        _: &UniqueLinesCaseSensitive,
10310        window: &mut Window,
10311        cx: &mut Context<Self>,
10312    ) {
10313        self.manipulate_immutable_lines(window, cx, |lines| {
10314            let mut seen = HashSet::default();
10315            lines.retain(|line| seen.insert(*line));
10316        })
10317    }
10318
10319    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10320        let Some(project) = self.project.clone() else {
10321            return;
10322        };
10323        self.reload(project, window, cx)
10324            .detach_and_notify_err(window, cx);
10325    }
10326
10327    pub fn restore_file(
10328        &mut self,
10329        _: &::git::RestoreFile,
10330        window: &mut Window,
10331        cx: &mut Context<Self>,
10332    ) {
10333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10334        let mut buffer_ids = HashSet::default();
10335        let snapshot = self.buffer().read(cx).snapshot(cx);
10336        for selection in self.selections.all::<usize>(cx) {
10337            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10338        }
10339
10340        let buffer = self.buffer().read(cx);
10341        let ranges = buffer_ids
10342            .into_iter()
10343            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10344            .collect::<Vec<_>>();
10345
10346        self.restore_hunks_in_ranges(ranges, window, cx);
10347    }
10348
10349    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10351        let selections = self
10352            .selections
10353            .all(cx)
10354            .into_iter()
10355            .map(|s| s.range())
10356            .collect();
10357        self.restore_hunks_in_ranges(selections, window, cx);
10358    }
10359
10360    pub fn restore_hunks_in_ranges(
10361        &mut self,
10362        ranges: Vec<Range<Point>>,
10363        window: &mut Window,
10364        cx: &mut Context<Editor>,
10365    ) {
10366        let mut revert_changes = HashMap::default();
10367        let chunk_by = self
10368            .snapshot(window, cx)
10369            .hunks_for_ranges(ranges)
10370            .into_iter()
10371            .chunk_by(|hunk| hunk.buffer_id);
10372        for (buffer_id, hunks) in &chunk_by {
10373            let hunks = hunks.collect::<Vec<_>>();
10374            for hunk in &hunks {
10375                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10376            }
10377            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10378        }
10379        drop(chunk_by);
10380        if !revert_changes.is_empty() {
10381            self.transact(window, cx, |editor, window, cx| {
10382                editor.restore(revert_changes, window, cx);
10383            });
10384        }
10385    }
10386
10387    pub fn open_active_item_in_terminal(
10388        &mut self,
10389        _: &OpenInTerminal,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10394            let project_path = buffer.read(cx).project_path(cx)?;
10395            let project = self.project.as_ref()?.read(cx);
10396            let entry = project.entry_for_path(&project_path, cx)?;
10397            let parent = match &entry.canonical_path {
10398                Some(canonical_path) => canonical_path.to_path_buf(),
10399                None => project.absolute_path(&project_path, cx)?,
10400            }
10401            .parent()?
10402            .to_path_buf();
10403            Some(parent)
10404        }) {
10405            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10406        }
10407    }
10408
10409    fn set_breakpoint_context_menu(
10410        &mut self,
10411        display_row: DisplayRow,
10412        position: Option<Anchor>,
10413        clicked_point: gpui::Point<Pixels>,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        let source = self
10418            .buffer
10419            .read(cx)
10420            .snapshot(cx)
10421            .anchor_before(Point::new(display_row.0, 0u32));
10422
10423        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10424
10425        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10426            self,
10427            source,
10428            clicked_point,
10429            context_menu,
10430            window,
10431            cx,
10432        );
10433    }
10434
10435    fn add_edit_breakpoint_block(
10436        &mut self,
10437        anchor: Anchor,
10438        breakpoint: &Breakpoint,
10439        edit_action: BreakpointPromptEditAction,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        let weak_editor = cx.weak_entity();
10444        let bp_prompt = cx.new(|cx| {
10445            BreakpointPromptEditor::new(
10446                weak_editor,
10447                anchor,
10448                breakpoint.clone(),
10449                edit_action,
10450                window,
10451                cx,
10452            )
10453        });
10454
10455        let height = bp_prompt.update(cx, |this, cx| {
10456            this.prompt
10457                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10458        });
10459        let cloned_prompt = bp_prompt.clone();
10460        let blocks = vec![BlockProperties {
10461            style: BlockStyle::Sticky,
10462            placement: BlockPlacement::Above(anchor),
10463            height: Some(height),
10464            render: Arc::new(move |cx| {
10465                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10466                cloned_prompt.clone().into_any_element()
10467            }),
10468            priority: 0,
10469        }];
10470
10471        let focus_handle = bp_prompt.focus_handle(cx);
10472        window.focus(&focus_handle);
10473
10474        let block_ids = self.insert_blocks(blocks, None, cx);
10475        bp_prompt.update(cx, |prompt, _| {
10476            prompt.add_block_ids(block_ids);
10477        });
10478    }
10479
10480    pub(crate) fn breakpoint_at_row(
10481        &self,
10482        row: u32,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) -> Option<(Anchor, Breakpoint)> {
10486        let snapshot = self.snapshot(window, cx);
10487        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10488
10489        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10490    }
10491
10492    pub(crate) fn breakpoint_at_anchor(
10493        &self,
10494        breakpoint_position: Anchor,
10495        snapshot: &EditorSnapshot,
10496        cx: &mut Context<Self>,
10497    ) -> Option<(Anchor, Breakpoint)> {
10498        let project = self.project.clone()?;
10499
10500        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10501            snapshot
10502                .buffer_snapshot
10503                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10504        })?;
10505
10506        let enclosing_excerpt = breakpoint_position.excerpt_id;
10507        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10508        let buffer_snapshot = buffer.read(cx).snapshot();
10509
10510        let row = buffer_snapshot
10511            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10512            .row;
10513
10514        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10515        let anchor_end = snapshot
10516            .buffer_snapshot
10517            .anchor_after(Point::new(row, line_len));
10518
10519        let bp = self
10520            .breakpoint_store
10521            .as_ref()?
10522            .read_with(cx, |breakpoint_store, cx| {
10523                breakpoint_store
10524                    .breakpoints(
10525                        &buffer,
10526                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10527                        &buffer_snapshot,
10528                        cx,
10529                    )
10530                    .next()
10531                    .and_then(|(bp, _)| {
10532                        let breakpoint_row = buffer_snapshot
10533                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10534                            .row;
10535
10536                        if breakpoint_row == row {
10537                            snapshot
10538                                .buffer_snapshot
10539                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10540                                .map(|position| (position, bp.bp.clone()))
10541                        } else {
10542                            None
10543                        }
10544                    })
10545            });
10546        bp
10547    }
10548
10549    pub fn edit_log_breakpoint(
10550        &mut self,
10551        _: &EditLogBreakpoint,
10552        window: &mut Window,
10553        cx: &mut Context<Self>,
10554    ) {
10555        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10556            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10557                message: None,
10558                state: BreakpointState::Enabled,
10559                condition: None,
10560                hit_condition: None,
10561            });
10562
10563            self.add_edit_breakpoint_block(
10564                anchor,
10565                &breakpoint,
10566                BreakpointPromptEditAction::Log,
10567                window,
10568                cx,
10569            );
10570        }
10571    }
10572
10573    fn breakpoints_at_cursors(
10574        &self,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10578        let snapshot = self.snapshot(window, cx);
10579        let cursors = self
10580            .selections
10581            .disjoint_anchors()
10582            .into_iter()
10583            .map(|selection| {
10584                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10585
10586                let breakpoint_position = self
10587                    .breakpoint_at_row(cursor_position.row, window, cx)
10588                    .map(|bp| bp.0)
10589                    .unwrap_or_else(|| {
10590                        snapshot
10591                            .display_snapshot
10592                            .buffer_snapshot
10593                            .anchor_after(Point::new(cursor_position.row, 0))
10594                    });
10595
10596                let breakpoint = self
10597                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10598                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10599
10600                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10601            })
10602            // 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.
10603            .collect::<HashMap<Anchor, _>>();
10604
10605        cursors.into_iter().collect()
10606    }
10607
10608    pub fn enable_breakpoint(
10609        &mut self,
10610        _: &crate::actions::EnableBreakpoint,
10611        window: &mut Window,
10612        cx: &mut Context<Self>,
10613    ) {
10614        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10615            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10616                continue;
10617            };
10618            self.edit_breakpoint_at_anchor(
10619                anchor,
10620                breakpoint,
10621                BreakpointEditAction::InvertState,
10622                cx,
10623            );
10624        }
10625    }
10626
10627    pub fn disable_breakpoint(
10628        &mut self,
10629        _: &crate::actions::DisableBreakpoint,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) {
10633        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10634            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10635                continue;
10636            };
10637            self.edit_breakpoint_at_anchor(
10638                anchor,
10639                breakpoint,
10640                BreakpointEditAction::InvertState,
10641                cx,
10642            );
10643        }
10644    }
10645
10646    pub fn toggle_breakpoint(
10647        &mut self,
10648        _: &crate::actions::ToggleBreakpoint,
10649        window: &mut Window,
10650        cx: &mut Context<Self>,
10651    ) {
10652        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10653            if let Some(breakpoint) = breakpoint {
10654                self.edit_breakpoint_at_anchor(
10655                    anchor,
10656                    breakpoint,
10657                    BreakpointEditAction::Toggle,
10658                    cx,
10659                );
10660            } else {
10661                self.edit_breakpoint_at_anchor(
10662                    anchor,
10663                    Breakpoint::new_standard(),
10664                    BreakpointEditAction::Toggle,
10665                    cx,
10666                );
10667            }
10668        }
10669    }
10670
10671    pub fn edit_breakpoint_at_anchor(
10672        &mut self,
10673        breakpoint_position: Anchor,
10674        breakpoint: Breakpoint,
10675        edit_action: BreakpointEditAction,
10676        cx: &mut Context<Self>,
10677    ) {
10678        let Some(breakpoint_store) = &self.breakpoint_store else {
10679            return;
10680        };
10681
10682        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10683            if breakpoint_position == Anchor::min() {
10684                self.buffer()
10685                    .read(cx)
10686                    .excerpt_buffer_ids()
10687                    .into_iter()
10688                    .next()
10689            } else {
10690                None
10691            }
10692        }) else {
10693            return;
10694        };
10695
10696        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10697            return;
10698        };
10699
10700        breakpoint_store.update(cx, |breakpoint_store, cx| {
10701            breakpoint_store.toggle_breakpoint(
10702                buffer,
10703                BreakpointWithPosition {
10704                    position: breakpoint_position.text_anchor,
10705                    bp: breakpoint,
10706                },
10707                edit_action,
10708                cx,
10709            );
10710        });
10711
10712        cx.notify();
10713    }
10714
10715    #[cfg(any(test, feature = "test-support"))]
10716    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10717        self.breakpoint_store.clone()
10718    }
10719
10720    pub fn prepare_restore_change(
10721        &self,
10722        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10723        hunk: &MultiBufferDiffHunk,
10724        cx: &mut App,
10725    ) -> Option<()> {
10726        if hunk.is_created_file() {
10727            return None;
10728        }
10729        let buffer = self.buffer.read(cx);
10730        let diff = buffer.diff_for(hunk.buffer_id)?;
10731        let buffer = buffer.buffer(hunk.buffer_id)?;
10732        let buffer = buffer.read(cx);
10733        let original_text = diff
10734            .read(cx)
10735            .base_text()
10736            .as_rope()
10737            .slice(hunk.diff_base_byte_range.clone());
10738        let buffer_snapshot = buffer.snapshot();
10739        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10740        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10741            probe
10742                .0
10743                .start
10744                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10745                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10746        }) {
10747            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10748            Some(())
10749        } else {
10750            None
10751        }
10752    }
10753
10754    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10755        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10756    }
10757
10758    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10759        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10760    }
10761
10762    fn manipulate_lines<M>(
10763        &mut self,
10764        window: &mut Window,
10765        cx: &mut Context<Self>,
10766        mut manipulate: M,
10767    ) where
10768        M: FnMut(&str) -> LineManipulationResult,
10769    {
10770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10771
10772        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10773        let buffer = self.buffer.read(cx).snapshot(cx);
10774
10775        let mut edits = Vec::new();
10776
10777        let selections = self.selections.all::<Point>(cx);
10778        let mut selections = selections.iter().peekable();
10779        let mut contiguous_row_selections = Vec::new();
10780        let mut new_selections = Vec::new();
10781        let mut added_lines = 0;
10782        let mut removed_lines = 0;
10783
10784        while let Some(selection) = selections.next() {
10785            let (start_row, end_row) = consume_contiguous_rows(
10786                &mut contiguous_row_selections,
10787                selection,
10788                &display_map,
10789                &mut selections,
10790            );
10791
10792            let start_point = Point::new(start_row.0, 0);
10793            let end_point = Point::new(
10794                end_row.previous_row().0,
10795                buffer.line_len(end_row.previous_row()),
10796            );
10797            let text = buffer
10798                .text_for_range(start_point..end_point)
10799                .collect::<String>();
10800
10801            let LineManipulationResult {
10802                new_text,
10803                line_count_before,
10804                line_count_after,
10805            } = manipulate(&text);
10806
10807            edits.push((start_point..end_point, new_text));
10808
10809            // Selections must change based on added and removed line count
10810            let start_row =
10811                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10812            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10813            new_selections.push(Selection {
10814                id: selection.id,
10815                start: start_row,
10816                end: end_row,
10817                goal: SelectionGoal::None,
10818                reversed: selection.reversed,
10819            });
10820
10821            if line_count_after > line_count_before {
10822                added_lines += line_count_after - line_count_before;
10823            } else if line_count_before > line_count_after {
10824                removed_lines += line_count_before - line_count_after;
10825            }
10826        }
10827
10828        self.transact(window, cx, |this, window, cx| {
10829            let buffer = this.buffer.update(cx, |buffer, cx| {
10830                buffer.edit(edits, None, cx);
10831                buffer.snapshot(cx)
10832            });
10833
10834            // Recalculate offsets on newly edited buffer
10835            let new_selections = new_selections
10836                .iter()
10837                .map(|s| {
10838                    let start_point = Point::new(s.start.0, 0);
10839                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10840                    Selection {
10841                        id: s.id,
10842                        start: buffer.point_to_offset(start_point),
10843                        end: buffer.point_to_offset(end_point),
10844                        goal: s.goal,
10845                        reversed: s.reversed,
10846                    }
10847                })
10848                .collect();
10849
10850            this.change_selections(Default::default(), window, cx, |s| {
10851                s.select(new_selections);
10852            });
10853
10854            this.request_autoscroll(Autoscroll::fit(), cx);
10855        });
10856    }
10857
10858    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10859        self.manipulate_text(window, cx, |text| {
10860            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10861            if has_upper_case_characters {
10862                text.to_lowercase()
10863            } else {
10864                text.to_uppercase()
10865            }
10866        })
10867    }
10868
10869    fn manipulate_immutable_lines<Fn>(
10870        &mut self,
10871        window: &mut Window,
10872        cx: &mut Context<Self>,
10873        mut callback: Fn,
10874    ) where
10875        Fn: FnMut(&mut Vec<&str>),
10876    {
10877        self.manipulate_lines(window, cx, |text| {
10878            let mut lines: Vec<&str> = text.split('\n').collect();
10879            let line_count_before = lines.len();
10880
10881            callback(&mut lines);
10882
10883            LineManipulationResult {
10884                new_text: lines.join("\n"),
10885                line_count_before,
10886                line_count_after: lines.len(),
10887            }
10888        });
10889    }
10890
10891    fn manipulate_mutable_lines<Fn>(
10892        &mut self,
10893        window: &mut Window,
10894        cx: &mut Context<Self>,
10895        mut callback: Fn,
10896    ) where
10897        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10898    {
10899        self.manipulate_lines(window, cx, |text| {
10900            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10901            let line_count_before = lines.len();
10902
10903            callback(&mut lines);
10904
10905            LineManipulationResult {
10906                new_text: lines.join("\n"),
10907                line_count_before,
10908                line_count_after: lines.len(),
10909            }
10910        });
10911    }
10912
10913    pub fn convert_indentation_to_spaces(
10914        &mut self,
10915        _: &ConvertIndentationToSpaces,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        let settings = self.buffer.read(cx).language_settings(cx);
10920        let tab_size = settings.tab_size.get() as usize;
10921
10922        self.manipulate_mutable_lines(window, cx, |lines| {
10923            // Allocates a reasonably sized scratch buffer once for the whole loop
10924            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10925            // Avoids recomputing spaces that could be inserted many times
10926            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10927                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10928                .collect();
10929
10930            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10931                let mut chars = line.as_ref().chars();
10932                let mut col = 0;
10933                let mut changed = false;
10934
10935                while let Some(ch) = chars.next() {
10936                    match ch {
10937                        ' ' => {
10938                            reindented_line.push(' ');
10939                            col += 1;
10940                        }
10941                        '\t' => {
10942                            // \t are converted to spaces depending on the current column
10943                            let spaces_len = tab_size - (col % tab_size);
10944                            reindented_line.extend(&space_cache[spaces_len - 1]);
10945                            col += spaces_len;
10946                            changed = true;
10947                        }
10948                        _ => {
10949                            // If we dont append before break, the character is consumed
10950                            reindented_line.push(ch);
10951                            break;
10952                        }
10953                    }
10954                }
10955
10956                if !changed {
10957                    reindented_line.clear();
10958                    continue;
10959                }
10960                // Append the rest of the line and replace old reference with new one
10961                reindented_line.extend(chars);
10962                *line = Cow::Owned(reindented_line.clone());
10963                reindented_line.clear();
10964            }
10965        });
10966    }
10967
10968    pub fn convert_indentation_to_tabs(
10969        &mut self,
10970        _: &ConvertIndentationToTabs,
10971        window: &mut Window,
10972        cx: &mut Context<Self>,
10973    ) {
10974        let settings = self.buffer.read(cx).language_settings(cx);
10975        let tab_size = settings.tab_size.get() as usize;
10976
10977        self.manipulate_mutable_lines(window, cx, |lines| {
10978            // Allocates a reasonably sized buffer once for the whole loop
10979            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10980            // Avoids recomputing spaces that could be inserted many times
10981            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10982                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10983                .collect();
10984
10985            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10986                let mut chars = line.chars();
10987                let mut spaces_count = 0;
10988                let mut first_non_indent_char = None;
10989                let mut changed = false;
10990
10991                while let Some(ch) = chars.next() {
10992                    match ch {
10993                        ' ' => {
10994                            // Keep track of spaces. Append \t when we reach tab_size
10995                            spaces_count += 1;
10996                            changed = true;
10997                            if spaces_count == tab_size {
10998                                reindented_line.push('\t');
10999                                spaces_count = 0;
11000                            }
11001                        }
11002                        '\t' => {
11003                            reindented_line.push('\t');
11004                            spaces_count = 0;
11005                        }
11006                        _ => {
11007                            // Dont append it yet, we might have remaining spaces
11008                            first_non_indent_char = Some(ch);
11009                            break;
11010                        }
11011                    }
11012                }
11013
11014                if !changed {
11015                    reindented_line.clear();
11016                    continue;
11017                }
11018                // Remaining spaces that didn't make a full tab stop
11019                if spaces_count > 0 {
11020                    reindented_line.extend(&space_cache[spaces_count - 1]);
11021                }
11022                // If we consume an extra character that was not indentation, add it back
11023                if let Some(extra_char) = first_non_indent_char {
11024                    reindented_line.push(extra_char);
11025                }
11026                // Append the rest of the line and replace old reference with new one
11027                reindented_line.extend(chars);
11028                *line = Cow::Owned(reindented_line.clone());
11029                reindented_line.clear();
11030            }
11031        });
11032    }
11033
11034    pub fn convert_to_upper_case(
11035        &mut self,
11036        _: &ConvertToUpperCase,
11037        window: &mut Window,
11038        cx: &mut Context<Self>,
11039    ) {
11040        self.manipulate_text(window, cx, |text| text.to_uppercase())
11041    }
11042
11043    pub fn convert_to_lower_case(
11044        &mut self,
11045        _: &ConvertToLowerCase,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        self.manipulate_text(window, cx, |text| text.to_lowercase())
11050    }
11051
11052    pub fn convert_to_title_case(
11053        &mut self,
11054        _: &ConvertToTitleCase,
11055        window: &mut Window,
11056        cx: &mut Context<Self>,
11057    ) {
11058        self.manipulate_text(window, cx, |text| {
11059            text.split('\n')
11060                .map(|line| line.to_case(Case::Title))
11061                .join("\n")
11062        })
11063    }
11064
11065    pub fn convert_to_snake_case(
11066        &mut self,
11067        _: &ConvertToSnakeCase,
11068        window: &mut Window,
11069        cx: &mut Context<Self>,
11070    ) {
11071        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11072    }
11073
11074    pub fn convert_to_kebab_case(
11075        &mut self,
11076        _: &ConvertToKebabCase,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11081    }
11082
11083    pub fn convert_to_upper_camel_case(
11084        &mut self,
11085        _: &ConvertToUpperCamelCase,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) {
11089        self.manipulate_text(window, cx, |text| {
11090            text.split('\n')
11091                .map(|line| line.to_case(Case::UpperCamel))
11092                .join("\n")
11093        })
11094    }
11095
11096    pub fn convert_to_lower_camel_case(
11097        &mut self,
11098        _: &ConvertToLowerCamelCase,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11103    }
11104
11105    pub fn convert_to_opposite_case(
11106        &mut self,
11107        _: &ConvertToOppositeCase,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        self.manipulate_text(window, cx, |text| {
11112            text.chars()
11113                .fold(String::with_capacity(text.len()), |mut t, c| {
11114                    if c.is_uppercase() {
11115                        t.extend(c.to_lowercase());
11116                    } else {
11117                        t.extend(c.to_uppercase());
11118                    }
11119                    t
11120                })
11121        })
11122    }
11123
11124    pub fn convert_to_rot13(
11125        &mut self,
11126        _: &ConvertToRot13,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        self.manipulate_text(window, cx, |text| {
11131            text.chars()
11132                .map(|c| match c {
11133                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11134                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11135                    _ => c,
11136                })
11137                .collect()
11138        })
11139    }
11140
11141    pub fn convert_to_rot47(
11142        &mut self,
11143        _: &ConvertToRot47,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146    ) {
11147        self.manipulate_text(window, cx, |text| {
11148            text.chars()
11149                .map(|c| {
11150                    let code_point = c as u32;
11151                    if code_point >= 33 && code_point <= 126 {
11152                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11153                    }
11154                    c
11155                })
11156                .collect()
11157        })
11158    }
11159
11160    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11161    where
11162        Fn: FnMut(&str) -> String,
11163    {
11164        let buffer = self.buffer.read(cx).snapshot(cx);
11165
11166        let mut new_selections = Vec::new();
11167        let mut edits = Vec::new();
11168        let mut selection_adjustment = 0i32;
11169
11170        for selection in self.selections.all::<usize>(cx) {
11171            let selection_is_empty = selection.is_empty();
11172
11173            let (start, end) = if selection_is_empty {
11174                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11175                (word_range.start, word_range.end)
11176            } else {
11177                (selection.start, selection.end)
11178            };
11179
11180            let text = buffer.text_for_range(start..end).collect::<String>();
11181            let old_length = text.len() as i32;
11182            let text = callback(&text);
11183
11184            new_selections.push(Selection {
11185                start: (start as i32 - selection_adjustment) as usize,
11186                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11187                goal: SelectionGoal::None,
11188                ..selection
11189            });
11190
11191            selection_adjustment += old_length - text.len() as i32;
11192
11193            edits.push((start..end, text));
11194        }
11195
11196        self.transact(window, cx, |this, window, cx| {
11197            this.buffer.update(cx, |buffer, cx| {
11198                buffer.edit(edits, None, cx);
11199            });
11200
11201            this.change_selections(Default::default(), window, cx, |s| {
11202                s.select(new_selections);
11203            });
11204
11205            this.request_autoscroll(Autoscroll::fit(), cx);
11206        });
11207    }
11208
11209    pub fn move_selection_on_drop(
11210        &mut self,
11211        selection: &Selection<Anchor>,
11212        target: DisplayPoint,
11213        is_cut: bool,
11214        window: &mut Window,
11215        cx: &mut Context<Self>,
11216    ) {
11217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11218        let buffer = &display_map.buffer_snapshot;
11219        let mut edits = Vec::new();
11220        let insert_point = display_map
11221            .clip_point(target, Bias::Left)
11222            .to_point(&display_map);
11223        let text = buffer
11224            .text_for_range(selection.start..selection.end)
11225            .collect::<String>();
11226        if is_cut {
11227            edits.push(((selection.start..selection.end), String::new()));
11228        }
11229        let insert_anchor = buffer.anchor_before(insert_point);
11230        edits.push(((insert_anchor..insert_anchor), text));
11231        let last_edit_start = insert_anchor.bias_left(buffer);
11232        let last_edit_end = insert_anchor.bias_right(buffer);
11233        self.transact(window, cx, |this, window, cx| {
11234            this.buffer.update(cx, |buffer, cx| {
11235                buffer.edit(edits, None, cx);
11236            });
11237            this.change_selections(Default::default(), window, cx, |s| {
11238                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11239            });
11240        });
11241    }
11242
11243    pub fn clear_selection_drag_state(&mut self) {
11244        self.selection_drag_state = SelectionDragState::None;
11245    }
11246
11247    pub fn duplicate(
11248        &mut self,
11249        upwards: bool,
11250        whole_lines: bool,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11255
11256        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11257        let buffer = &display_map.buffer_snapshot;
11258        let selections = self.selections.all::<Point>(cx);
11259
11260        let mut edits = Vec::new();
11261        let mut selections_iter = selections.iter().peekable();
11262        while let Some(selection) = selections_iter.next() {
11263            let mut rows = selection.spanned_rows(false, &display_map);
11264            // duplicate line-wise
11265            if whole_lines || selection.start == selection.end {
11266                // Avoid duplicating the same lines twice.
11267                while let Some(next_selection) = selections_iter.peek() {
11268                    let next_rows = next_selection.spanned_rows(false, &display_map);
11269                    if next_rows.start < rows.end {
11270                        rows.end = next_rows.end;
11271                        selections_iter.next().unwrap();
11272                    } else {
11273                        break;
11274                    }
11275                }
11276
11277                // Copy the text from the selected row region and splice it either at the start
11278                // or end of the region.
11279                let start = Point::new(rows.start.0, 0);
11280                let end = Point::new(
11281                    rows.end.previous_row().0,
11282                    buffer.line_len(rows.end.previous_row()),
11283                );
11284                let text = buffer
11285                    .text_for_range(start..end)
11286                    .chain(Some("\n"))
11287                    .collect::<String>();
11288                let insert_location = if upwards {
11289                    Point::new(rows.end.0, 0)
11290                } else {
11291                    start
11292                };
11293                edits.push((insert_location..insert_location, text));
11294            } else {
11295                // duplicate character-wise
11296                let start = selection.start;
11297                let end = selection.end;
11298                let text = buffer.text_for_range(start..end).collect::<String>();
11299                edits.push((selection.end..selection.end, text));
11300            }
11301        }
11302
11303        self.transact(window, cx, |this, _, cx| {
11304            this.buffer.update(cx, |buffer, cx| {
11305                buffer.edit(edits, None, cx);
11306            });
11307
11308            this.request_autoscroll(Autoscroll::fit(), cx);
11309        });
11310    }
11311
11312    pub fn duplicate_line_up(
11313        &mut self,
11314        _: &DuplicateLineUp,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317    ) {
11318        self.duplicate(true, true, window, cx);
11319    }
11320
11321    pub fn duplicate_line_down(
11322        &mut self,
11323        _: &DuplicateLineDown,
11324        window: &mut Window,
11325        cx: &mut Context<Self>,
11326    ) {
11327        self.duplicate(false, true, window, cx);
11328    }
11329
11330    pub fn duplicate_selection(
11331        &mut self,
11332        _: &DuplicateSelection,
11333        window: &mut Window,
11334        cx: &mut Context<Self>,
11335    ) {
11336        self.duplicate(false, false, window, cx);
11337    }
11338
11339    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11341        if self.mode.is_single_line() {
11342            cx.propagate();
11343            return;
11344        }
11345
11346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11347        let buffer = self.buffer.read(cx).snapshot(cx);
11348
11349        let mut edits = Vec::new();
11350        let mut unfold_ranges = Vec::new();
11351        let mut refold_creases = Vec::new();
11352
11353        let selections = self.selections.all::<Point>(cx);
11354        let mut selections = selections.iter().peekable();
11355        let mut contiguous_row_selections = Vec::new();
11356        let mut new_selections = Vec::new();
11357
11358        while let Some(selection) = selections.next() {
11359            // Find all the selections that span a contiguous row range
11360            let (start_row, end_row) = consume_contiguous_rows(
11361                &mut contiguous_row_selections,
11362                selection,
11363                &display_map,
11364                &mut selections,
11365            );
11366
11367            // Move the text spanned by the row range to be before the line preceding the row range
11368            if start_row.0 > 0 {
11369                let range_to_move = Point::new(
11370                    start_row.previous_row().0,
11371                    buffer.line_len(start_row.previous_row()),
11372                )
11373                    ..Point::new(
11374                        end_row.previous_row().0,
11375                        buffer.line_len(end_row.previous_row()),
11376                    );
11377                let insertion_point = display_map
11378                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11379                    .0;
11380
11381                // Don't move lines across excerpts
11382                if buffer
11383                    .excerpt_containing(insertion_point..range_to_move.end)
11384                    .is_some()
11385                {
11386                    let text = buffer
11387                        .text_for_range(range_to_move.clone())
11388                        .flat_map(|s| s.chars())
11389                        .skip(1)
11390                        .chain(['\n'])
11391                        .collect::<String>();
11392
11393                    edits.push((
11394                        buffer.anchor_after(range_to_move.start)
11395                            ..buffer.anchor_before(range_to_move.end),
11396                        String::new(),
11397                    ));
11398                    let insertion_anchor = buffer.anchor_after(insertion_point);
11399                    edits.push((insertion_anchor..insertion_anchor, text));
11400
11401                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11402
11403                    // Move selections up
11404                    new_selections.extend(contiguous_row_selections.drain(..).map(
11405                        |mut selection| {
11406                            selection.start.row -= row_delta;
11407                            selection.end.row -= row_delta;
11408                            selection
11409                        },
11410                    ));
11411
11412                    // Move folds up
11413                    unfold_ranges.push(range_to_move.clone());
11414                    for fold in display_map.folds_in_range(
11415                        buffer.anchor_before(range_to_move.start)
11416                            ..buffer.anchor_after(range_to_move.end),
11417                    ) {
11418                        let mut start = fold.range.start.to_point(&buffer);
11419                        let mut end = fold.range.end.to_point(&buffer);
11420                        start.row -= row_delta;
11421                        end.row -= row_delta;
11422                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11423                    }
11424                }
11425            }
11426
11427            // If we didn't move line(s), preserve the existing selections
11428            new_selections.append(&mut contiguous_row_selections);
11429        }
11430
11431        self.transact(window, cx, |this, window, cx| {
11432            this.unfold_ranges(&unfold_ranges, true, true, cx);
11433            this.buffer.update(cx, |buffer, cx| {
11434                for (range, text) in edits {
11435                    buffer.edit([(range, text)], None, cx);
11436                }
11437            });
11438            this.fold_creases(refold_creases, true, window, cx);
11439            this.change_selections(Default::default(), window, cx, |s| {
11440                s.select(new_selections);
11441            })
11442        });
11443    }
11444
11445    pub fn move_line_down(
11446        &mut self,
11447        _: &MoveLineDown,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11452        if self.mode.is_single_line() {
11453            cx.propagate();
11454            return;
11455        }
11456
11457        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11458        let buffer = self.buffer.read(cx).snapshot(cx);
11459
11460        let mut edits = Vec::new();
11461        let mut unfold_ranges = Vec::new();
11462        let mut refold_creases = Vec::new();
11463
11464        let selections = self.selections.all::<Point>(cx);
11465        let mut selections = selections.iter().peekable();
11466        let mut contiguous_row_selections = Vec::new();
11467        let mut new_selections = Vec::new();
11468
11469        while let Some(selection) = selections.next() {
11470            // Find all the selections that span a contiguous row range
11471            let (start_row, end_row) = consume_contiguous_rows(
11472                &mut contiguous_row_selections,
11473                selection,
11474                &display_map,
11475                &mut selections,
11476            );
11477
11478            // Move the text spanned by the row range to be after the last line of the row range
11479            if end_row.0 <= buffer.max_point().row {
11480                let range_to_move =
11481                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11482                let insertion_point = display_map
11483                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11484                    .0;
11485
11486                // Don't move lines across excerpt boundaries
11487                if buffer
11488                    .excerpt_containing(range_to_move.start..insertion_point)
11489                    .is_some()
11490                {
11491                    let mut text = String::from("\n");
11492                    text.extend(buffer.text_for_range(range_to_move.clone()));
11493                    text.pop(); // Drop trailing newline
11494                    edits.push((
11495                        buffer.anchor_after(range_to_move.start)
11496                            ..buffer.anchor_before(range_to_move.end),
11497                        String::new(),
11498                    ));
11499                    let insertion_anchor = buffer.anchor_after(insertion_point);
11500                    edits.push((insertion_anchor..insertion_anchor, text));
11501
11502                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11503
11504                    // Move selections down
11505                    new_selections.extend(contiguous_row_selections.drain(..).map(
11506                        |mut selection| {
11507                            selection.start.row += row_delta;
11508                            selection.end.row += row_delta;
11509                            selection
11510                        },
11511                    ));
11512
11513                    // Move folds down
11514                    unfold_ranges.push(range_to_move.clone());
11515                    for fold in display_map.folds_in_range(
11516                        buffer.anchor_before(range_to_move.start)
11517                            ..buffer.anchor_after(range_to_move.end),
11518                    ) {
11519                        let mut start = fold.range.start.to_point(&buffer);
11520                        let mut end = fold.range.end.to_point(&buffer);
11521                        start.row += row_delta;
11522                        end.row += row_delta;
11523                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11524                    }
11525                }
11526            }
11527
11528            // If we didn't move line(s), preserve the existing selections
11529            new_selections.append(&mut contiguous_row_selections);
11530        }
11531
11532        self.transact(window, cx, |this, window, cx| {
11533            this.unfold_ranges(&unfold_ranges, true, true, cx);
11534            this.buffer.update(cx, |buffer, cx| {
11535                for (range, text) in edits {
11536                    buffer.edit([(range, text)], None, cx);
11537                }
11538            });
11539            this.fold_creases(refold_creases, true, window, cx);
11540            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11541        });
11542    }
11543
11544    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11546        let text_layout_details = &self.text_layout_details(window);
11547        self.transact(window, cx, |this, window, cx| {
11548            let edits = this.change_selections(Default::default(), window, cx, |s| {
11549                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11550                s.move_with(|display_map, selection| {
11551                    if !selection.is_empty() {
11552                        return;
11553                    }
11554
11555                    let mut head = selection.head();
11556                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11557                    if head.column() == display_map.line_len(head.row()) {
11558                        transpose_offset = display_map
11559                            .buffer_snapshot
11560                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11561                    }
11562
11563                    if transpose_offset == 0 {
11564                        return;
11565                    }
11566
11567                    *head.column_mut() += 1;
11568                    head = display_map.clip_point(head, Bias::Right);
11569                    let goal = SelectionGoal::HorizontalPosition(
11570                        display_map
11571                            .x_for_display_point(head, text_layout_details)
11572                            .into(),
11573                    );
11574                    selection.collapse_to(head, goal);
11575
11576                    let transpose_start = display_map
11577                        .buffer_snapshot
11578                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11579                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11580                        let transpose_end = display_map
11581                            .buffer_snapshot
11582                            .clip_offset(transpose_offset + 1, Bias::Right);
11583                        if let Some(ch) =
11584                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11585                        {
11586                            edits.push((transpose_start..transpose_offset, String::new()));
11587                            edits.push((transpose_end..transpose_end, ch.to_string()));
11588                        }
11589                    }
11590                });
11591                edits
11592            });
11593            this.buffer
11594                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11595            let selections = this.selections.all::<usize>(cx);
11596            this.change_selections(Default::default(), window, cx, |s| {
11597                s.select(selections);
11598            });
11599        });
11600    }
11601
11602    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11604        if self.mode.is_single_line() {
11605            cx.propagate();
11606            return;
11607        }
11608
11609        self.rewrap_impl(RewrapOptions::default(), cx)
11610    }
11611
11612    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11613        let buffer = self.buffer.read(cx).snapshot(cx);
11614        let selections = self.selections.all::<Point>(cx);
11615
11616        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11617        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11618            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11619                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11620                .peekable();
11621
11622            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11623                row
11624            } else {
11625                return Vec::new();
11626            };
11627
11628            let language_settings = buffer.language_settings_at(selection.head(), cx);
11629            let language_scope = buffer.language_scope_at(selection.head());
11630
11631            let indent_and_prefix_for_row =
11632                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11633                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11634                    let (comment_prefix, rewrap_prefix) =
11635                        if let Some(language_scope) = &language_scope {
11636                            let indent_end = Point::new(row, indent.len);
11637                            let comment_prefix = language_scope
11638                                .line_comment_prefixes()
11639                                .iter()
11640                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11641                                .map(|prefix| prefix.to_string());
11642                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11643                            let line_text_after_indent = buffer
11644                                .text_for_range(indent_end..line_end)
11645                                .collect::<String>();
11646                            let rewrap_prefix = language_scope
11647                                .rewrap_prefixes()
11648                                .iter()
11649                                .find_map(|prefix_regex| {
11650                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11651                                        if mat.start() == 0 {
11652                                            Some(mat.as_str().to_string())
11653                                        } else {
11654                                            None
11655                                        }
11656                                    })
11657                                })
11658                                .flatten();
11659                            (comment_prefix, rewrap_prefix)
11660                        } else {
11661                            (None, None)
11662                        };
11663                    (indent, comment_prefix, rewrap_prefix)
11664                };
11665
11666            let mut ranges = Vec::new();
11667            let from_empty_selection = selection.is_empty();
11668
11669            let mut current_range_start = first_row;
11670            let mut prev_row = first_row;
11671            let (
11672                mut current_range_indent,
11673                mut current_range_comment_prefix,
11674                mut current_range_rewrap_prefix,
11675            ) = indent_and_prefix_for_row(first_row);
11676
11677            for row in non_blank_rows_iter.skip(1) {
11678                let has_paragraph_break = row > prev_row + 1;
11679
11680                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11681                    indent_and_prefix_for_row(row);
11682
11683                let has_indent_change = row_indent != current_range_indent;
11684                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11685
11686                let has_boundary_change = has_comment_change
11687                    || row_rewrap_prefix.is_some()
11688                    || (has_indent_change && current_range_comment_prefix.is_some());
11689
11690                if has_paragraph_break || has_boundary_change {
11691                    ranges.push((
11692                        language_settings.clone(),
11693                        Point::new(current_range_start, 0)
11694                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11695                        current_range_indent,
11696                        current_range_comment_prefix.clone(),
11697                        current_range_rewrap_prefix.clone(),
11698                        from_empty_selection,
11699                    ));
11700                    current_range_start = row;
11701                    current_range_indent = row_indent;
11702                    current_range_comment_prefix = row_comment_prefix;
11703                    current_range_rewrap_prefix = row_rewrap_prefix;
11704                }
11705                prev_row = row;
11706            }
11707
11708            ranges.push((
11709                language_settings.clone(),
11710                Point::new(current_range_start, 0)
11711                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11712                current_range_indent,
11713                current_range_comment_prefix,
11714                current_range_rewrap_prefix,
11715                from_empty_selection,
11716            ));
11717
11718            ranges
11719        });
11720
11721        let mut edits = Vec::new();
11722        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11723
11724        for (
11725            language_settings,
11726            wrap_range,
11727            indent_size,
11728            comment_prefix,
11729            rewrap_prefix,
11730            from_empty_selection,
11731        ) in wrap_ranges
11732        {
11733            let mut start_row = wrap_range.start.row;
11734            let mut end_row = wrap_range.end.row;
11735
11736            // Skip selections that overlap with a range that has already been rewrapped.
11737            let selection_range = start_row..end_row;
11738            if rewrapped_row_ranges
11739                .iter()
11740                .any(|range| range.overlaps(&selection_range))
11741            {
11742                continue;
11743            }
11744
11745            let tab_size = language_settings.tab_size;
11746
11747            let indent_prefix = indent_size.chars().collect::<String>();
11748            let mut line_prefix = indent_prefix.clone();
11749            let mut inside_comment = false;
11750            if let Some(prefix) = &comment_prefix {
11751                line_prefix.push_str(prefix);
11752                inside_comment = true;
11753            }
11754            if let Some(prefix) = &rewrap_prefix {
11755                line_prefix.push_str(prefix);
11756            }
11757
11758            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11759                RewrapBehavior::InComments => inside_comment,
11760                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11761                RewrapBehavior::Anywhere => true,
11762            };
11763
11764            let should_rewrap = options.override_language_settings
11765                || allow_rewrap_based_on_language
11766                || self.hard_wrap.is_some();
11767            if !should_rewrap {
11768                continue;
11769            }
11770
11771            if from_empty_selection {
11772                'expand_upwards: while start_row > 0 {
11773                    let prev_row = start_row - 1;
11774                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11775                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11776                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11777                    {
11778                        start_row = prev_row;
11779                    } else {
11780                        break 'expand_upwards;
11781                    }
11782                }
11783
11784                'expand_downwards: while end_row < buffer.max_point().row {
11785                    let next_row = end_row + 1;
11786                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11787                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11788                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11789                    {
11790                        end_row = next_row;
11791                    } else {
11792                        break 'expand_downwards;
11793                    }
11794                }
11795            }
11796
11797            let start = Point::new(start_row, 0);
11798            let start_offset = start.to_offset(&buffer);
11799            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11800            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11801            let Some(lines_without_prefixes) = selection_text
11802                .lines()
11803                .enumerate()
11804                .map(|(ix, line)| {
11805                    let line_trimmed = line.trim_start();
11806                    if rewrap_prefix.is_some() && ix > 0 {
11807                        Ok(line_trimmed)
11808                    } else {
11809                        line_trimmed
11810                            .strip_prefix(&line_prefix.trim_start())
11811                            .with_context(|| {
11812                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11813                            })
11814                    }
11815                })
11816                .collect::<Result<Vec<_>, _>>()
11817                .log_err()
11818            else {
11819                continue;
11820            };
11821
11822            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11823                buffer
11824                    .language_settings_at(Point::new(start_row, 0), cx)
11825                    .preferred_line_length as usize
11826            });
11827
11828            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11829                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11830            } else {
11831                line_prefix.clone()
11832            };
11833
11834            let wrapped_text = wrap_with_prefix(
11835                line_prefix,
11836                subsequent_lines_prefix,
11837                lines_without_prefixes.join("\n"),
11838                wrap_column,
11839                tab_size,
11840                options.preserve_existing_whitespace,
11841            );
11842
11843            // TODO: should always use char-based diff while still supporting cursor behavior that
11844            // matches vim.
11845            let mut diff_options = DiffOptions::default();
11846            if options.override_language_settings {
11847                diff_options.max_word_diff_len = 0;
11848                diff_options.max_word_diff_line_count = 0;
11849            } else {
11850                diff_options.max_word_diff_len = usize::MAX;
11851                diff_options.max_word_diff_line_count = usize::MAX;
11852            }
11853
11854            for (old_range, new_text) in
11855                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11856            {
11857                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11858                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11859                edits.push((edit_start..edit_end, new_text));
11860            }
11861
11862            rewrapped_row_ranges.push(start_row..=end_row);
11863        }
11864
11865        self.buffer
11866            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11867    }
11868
11869    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11870        let mut text = String::new();
11871        let buffer = self.buffer.read(cx).snapshot(cx);
11872        let mut selections = self.selections.all::<Point>(cx);
11873        let mut clipboard_selections = Vec::with_capacity(selections.len());
11874        {
11875            let max_point = buffer.max_point();
11876            let mut is_first = true;
11877            for selection in &mut selections {
11878                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11879                if is_entire_line {
11880                    selection.start = Point::new(selection.start.row, 0);
11881                    if !selection.is_empty() && selection.end.column == 0 {
11882                        selection.end = cmp::min(max_point, selection.end);
11883                    } else {
11884                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11885                    }
11886                    selection.goal = SelectionGoal::None;
11887                }
11888                if is_first {
11889                    is_first = false;
11890                } else {
11891                    text += "\n";
11892                }
11893                let mut len = 0;
11894                for chunk in buffer.text_for_range(selection.start..selection.end) {
11895                    text.push_str(chunk);
11896                    len += chunk.len();
11897                }
11898                clipboard_selections.push(ClipboardSelection {
11899                    len,
11900                    is_entire_line,
11901                    first_line_indent: buffer
11902                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11903                        .len,
11904                });
11905            }
11906        }
11907
11908        self.transact(window, cx, |this, window, cx| {
11909            this.change_selections(Default::default(), window, cx, |s| {
11910                s.select(selections);
11911            });
11912            this.insert("", window, cx);
11913        });
11914        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11915    }
11916
11917    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11919        let item = self.cut_common(window, cx);
11920        cx.write_to_clipboard(item);
11921    }
11922
11923    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11925        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11926            s.move_with(|snapshot, sel| {
11927                if sel.is_empty() {
11928                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11929                }
11930            });
11931        });
11932        let item = self.cut_common(window, cx);
11933        cx.set_global(KillRing(item))
11934    }
11935
11936    pub fn kill_ring_yank(
11937        &mut self,
11938        _: &KillRingYank,
11939        window: &mut Window,
11940        cx: &mut Context<Self>,
11941    ) {
11942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11943        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11944            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11945                (kill_ring.text().to_string(), kill_ring.metadata_json())
11946            } else {
11947                return;
11948            }
11949        } else {
11950            return;
11951        };
11952        self.do_paste(&text, metadata, false, window, cx);
11953    }
11954
11955    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11956        self.do_copy(true, cx);
11957    }
11958
11959    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11960        self.do_copy(false, cx);
11961    }
11962
11963    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11964        let selections = self.selections.all::<Point>(cx);
11965        let buffer = self.buffer.read(cx).read(cx);
11966        let mut text = String::new();
11967
11968        let mut clipboard_selections = Vec::with_capacity(selections.len());
11969        {
11970            let max_point = buffer.max_point();
11971            let mut is_first = true;
11972            for selection in &selections {
11973                let mut start = selection.start;
11974                let mut end = selection.end;
11975                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11976                if is_entire_line {
11977                    start = Point::new(start.row, 0);
11978                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11979                }
11980
11981                let mut trimmed_selections = Vec::new();
11982                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11983                    let row = MultiBufferRow(start.row);
11984                    let first_indent = buffer.indent_size_for_line(row);
11985                    if first_indent.len == 0 || start.column > first_indent.len {
11986                        trimmed_selections.push(start..end);
11987                    } else {
11988                        trimmed_selections.push(
11989                            Point::new(row.0, first_indent.len)
11990                                ..Point::new(row.0, buffer.line_len(row)),
11991                        );
11992                        for row in start.row + 1..=end.row {
11993                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11994                            if row == end.row {
11995                                line_len = end.column;
11996                            }
11997                            if line_len == 0 {
11998                                trimmed_selections
11999                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12000                                continue;
12001                            }
12002                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12003                            if row_indent_size.len >= first_indent.len {
12004                                trimmed_selections.push(
12005                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12006                                );
12007                            } else {
12008                                trimmed_selections.clear();
12009                                trimmed_selections.push(start..end);
12010                                break;
12011                            }
12012                        }
12013                    }
12014                } else {
12015                    trimmed_selections.push(start..end);
12016                }
12017
12018                for trimmed_range in trimmed_selections {
12019                    if is_first {
12020                        is_first = false;
12021                    } else {
12022                        text += "\n";
12023                    }
12024                    let mut len = 0;
12025                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12026                        text.push_str(chunk);
12027                        len += chunk.len();
12028                    }
12029                    clipboard_selections.push(ClipboardSelection {
12030                        len,
12031                        is_entire_line,
12032                        first_line_indent: buffer
12033                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12034                            .len,
12035                    });
12036                }
12037            }
12038        }
12039
12040        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12041            text,
12042            clipboard_selections,
12043        ));
12044    }
12045
12046    pub fn do_paste(
12047        &mut self,
12048        text: &String,
12049        clipboard_selections: Option<Vec<ClipboardSelection>>,
12050        handle_entire_lines: bool,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        if self.read_only(cx) {
12055            return;
12056        }
12057
12058        let clipboard_text = Cow::Borrowed(text);
12059
12060        self.transact(window, cx, |this, window, cx| {
12061            if let Some(mut clipboard_selections) = clipboard_selections {
12062                let old_selections = this.selections.all::<usize>(cx);
12063                let all_selections_were_entire_line =
12064                    clipboard_selections.iter().all(|s| s.is_entire_line);
12065                let first_selection_indent_column =
12066                    clipboard_selections.first().map(|s| s.first_line_indent);
12067                if clipboard_selections.len() != old_selections.len() {
12068                    clipboard_selections.drain(..);
12069                }
12070                let cursor_offset = this.selections.last::<usize>(cx).head();
12071                let mut auto_indent_on_paste = true;
12072
12073                this.buffer.update(cx, |buffer, cx| {
12074                    let snapshot = buffer.read(cx);
12075                    auto_indent_on_paste = snapshot
12076                        .language_settings_at(cursor_offset, cx)
12077                        .auto_indent_on_paste;
12078
12079                    let mut start_offset = 0;
12080                    let mut edits = Vec::new();
12081                    let mut original_indent_columns = Vec::new();
12082                    for (ix, selection) in old_selections.iter().enumerate() {
12083                        let to_insert;
12084                        let entire_line;
12085                        let original_indent_column;
12086                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12087                            let end_offset = start_offset + clipboard_selection.len;
12088                            to_insert = &clipboard_text[start_offset..end_offset];
12089                            entire_line = clipboard_selection.is_entire_line;
12090                            start_offset = end_offset + 1;
12091                            original_indent_column = Some(clipboard_selection.first_line_indent);
12092                        } else {
12093                            to_insert = clipboard_text.as_str();
12094                            entire_line = all_selections_were_entire_line;
12095                            original_indent_column = first_selection_indent_column
12096                        }
12097
12098                        // If the corresponding selection was empty when this slice of the
12099                        // clipboard text was written, then the entire line containing the
12100                        // selection was copied. If this selection is also currently empty,
12101                        // then paste the line before the current line of the buffer.
12102                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12103                            let column = selection.start.to_point(&snapshot).column as usize;
12104                            let line_start = selection.start - column;
12105                            line_start..line_start
12106                        } else {
12107                            selection.range()
12108                        };
12109
12110                        edits.push((range, to_insert));
12111                        original_indent_columns.push(original_indent_column);
12112                    }
12113                    drop(snapshot);
12114
12115                    buffer.edit(
12116                        edits,
12117                        if auto_indent_on_paste {
12118                            Some(AutoindentMode::Block {
12119                                original_indent_columns,
12120                            })
12121                        } else {
12122                            None
12123                        },
12124                        cx,
12125                    );
12126                });
12127
12128                let selections = this.selections.all::<usize>(cx);
12129                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12130            } else {
12131                this.insert(&clipboard_text, window, cx);
12132            }
12133        });
12134    }
12135
12136    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12137        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12138        if let Some(item) = cx.read_from_clipboard() {
12139            let entries = item.entries();
12140
12141            match entries.first() {
12142                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12143                // of all the pasted entries.
12144                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12145                    .do_paste(
12146                        clipboard_string.text(),
12147                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12148                        true,
12149                        window,
12150                        cx,
12151                    ),
12152                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12153            }
12154        }
12155    }
12156
12157    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12158        if self.read_only(cx) {
12159            return;
12160        }
12161
12162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12163
12164        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12165            if let Some((selections, _)) =
12166                self.selection_history.transaction(transaction_id).cloned()
12167            {
12168                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12169                    s.select_anchors(selections.to_vec());
12170                });
12171            } else {
12172                log::error!(
12173                    "No entry in selection_history found for undo. \
12174                     This may correspond to a bug where undo does not update the selection. \
12175                     If this is occurring, please add details to \
12176                     https://github.com/zed-industries/zed/issues/22692"
12177                );
12178            }
12179            self.request_autoscroll(Autoscroll::fit(), cx);
12180            self.unmark_text(window, cx);
12181            self.refresh_inline_completion(true, false, window, cx);
12182            cx.emit(EditorEvent::Edited { transaction_id });
12183            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12184        }
12185    }
12186
12187    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12188        if self.read_only(cx) {
12189            return;
12190        }
12191
12192        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12193
12194        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12195            if let Some((_, Some(selections))) =
12196                self.selection_history.transaction(transaction_id).cloned()
12197            {
12198                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12199                    s.select_anchors(selections.to_vec());
12200                });
12201            } else {
12202                log::error!(
12203                    "No entry in selection_history found for redo. \
12204                     This may correspond to a bug where undo does not update the selection. \
12205                     If this is occurring, please add details to \
12206                     https://github.com/zed-industries/zed/issues/22692"
12207                );
12208            }
12209            self.request_autoscroll(Autoscroll::fit(), cx);
12210            self.unmark_text(window, cx);
12211            self.refresh_inline_completion(true, false, window, cx);
12212            cx.emit(EditorEvent::Edited { transaction_id });
12213        }
12214    }
12215
12216    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12217        self.buffer
12218            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12219    }
12220
12221    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12222        self.buffer
12223            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12224    }
12225
12226    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12228        self.change_selections(Default::default(), window, cx, |s| {
12229            s.move_with(|map, selection| {
12230                let cursor = if selection.is_empty() {
12231                    movement::left(map, selection.start)
12232                } else {
12233                    selection.start
12234                };
12235                selection.collapse_to(cursor, SelectionGoal::None);
12236            });
12237        })
12238    }
12239
12240    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12242        self.change_selections(Default::default(), window, cx, |s| {
12243            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12244        })
12245    }
12246
12247    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12249        self.change_selections(Default::default(), window, cx, |s| {
12250            s.move_with(|map, selection| {
12251                let cursor = if selection.is_empty() {
12252                    movement::right(map, selection.end)
12253                } else {
12254                    selection.end
12255                };
12256                selection.collapse_to(cursor, SelectionGoal::None)
12257            });
12258        })
12259    }
12260
12261    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12263        self.change_selections(Default::default(), window, cx, |s| {
12264            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12265        })
12266    }
12267
12268    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12269        if self.take_rename(true, window, cx).is_some() {
12270            return;
12271        }
12272
12273        if self.mode.is_single_line() {
12274            cx.propagate();
12275            return;
12276        }
12277
12278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12279
12280        let text_layout_details = &self.text_layout_details(window);
12281        let selection_count = self.selections.count();
12282        let first_selection = self.selections.first_anchor();
12283
12284        self.change_selections(Default::default(), window, cx, |s| {
12285            s.move_with(|map, selection| {
12286                if !selection.is_empty() {
12287                    selection.goal = SelectionGoal::None;
12288                }
12289                let (cursor, goal) = movement::up(
12290                    map,
12291                    selection.start,
12292                    selection.goal,
12293                    false,
12294                    text_layout_details,
12295                );
12296                selection.collapse_to(cursor, goal);
12297            });
12298        });
12299
12300        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12301        {
12302            cx.propagate();
12303        }
12304    }
12305
12306    pub fn move_up_by_lines(
12307        &mut self,
12308        action: &MoveUpByLines,
12309        window: &mut Window,
12310        cx: &mut Context<Self>,
12311    ) {
12312        if self.take_rename(true, window, cx).is_some() {
12313            return;
12314        }
12315
12316        if self.mode.is_single_line() {
12317            cx.propagate();
12318            return;
12319        }
12320
12321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12322
12323        let text_layout_details = &self.text_layout_details(window);
12324
12325        self.change_selections(Default::default(), window, cx, |s| {
12326            s.move_with(|map, selection| {
12327                if !selection.is_empty() {
12328                    selection.goal = SelectionGoal::None;
12329                }
12330                let (cursor, goal) = movement::up_by_rows(
12331                    map,
12332                    selection.start,
12333                    action.lines,
12334                    selection.goal,
12335                    false,
12336                    text_layout_details,
12337                );
12338                selection.collapse_to(cursor, goal);
12339            });
12340        })
12341    }
12342
12343    pub fn move_down_by_lines(
12344        &mut self,
12345        action: &MoveDownByLines,
12346        window: &mut Window,
12347        cx: &mut Context<Self>,
12348    ) {
12349        if self.take_rename(true, window, cx).is_some() {
12350            return;
12351        }
12352
12353        if self.mode.is_single_line() {
12354            cx.propagate();
12355            return;
12356        }
12357
12358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12359
12360        let text_layout_details = &self.text_layout_details(window);
12361
12362        self.change_selections(Default::default(), window, cx, |s| {
12363            s.move_with(|map, selection| {
12364                if !selection.is_empty() {
12365                    selection.goal = SelectionGoal::None;
12366                }
12367                let (cursor, goal) = movement::down_by_rows(
12368                    map,
12369                    selection.start,
12370                    action.lines,
12371                    selection.goal,
12372                    false,
12373                    text_layout_details,
12374                );
12375                selection.collapse_to(cursor, goal);
12376            });
12377        })
12378    }
12379
12380    pub fn select_down_by_lines(
12381        &mut self,
12382        action: &SelectDownByLines,
12383        window: &mut Window,
12384        cx: &mut Context<Self>,
12385    ) {
12386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12387        let text_layout_details = &self.text_layout_details(window);
12388        self.change_selections(Default::default(), window, cx, |s| {
12389            s.move_heads_with(|map, head, goal| {
12390                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12391            })
12392        })
12393    }
12394
12395    pub fn select_up_by_lines(
12396        &mut self,
12397        action: &SelectUpByLines,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12402        let text_layout_details = &self.text_layout_details(window);
12403        self.change_selections(Default::default(), window, cx, |s| {
12404            s.move_heads_with(|map, head, goal| {
12405                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12406            })
12407        })
12408    }
12409
12410    pub fn select_page_up(
12411        &mut self,
12412        _: &SelectPageUp,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        let Some(row_count) = self.visible_row_count() else {
12417            return;
12418        };
12419
12420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12421
12422        let text_layout_details = &self.text_layout_details(window);
12423
12424        self.change_selections(Default::default(), window, cx, |s| {
12425            s.move_heads_with(|map, head, goal| {
12426                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12427            })
12428        })
12429    }
12430
12431    pub fn move_page_up(
12432        &mut self,
12433        action: &MovePageUp,
12434        window: &mut Window,
12435        cx: &mut Context<Self>,
12436    ) {
12437        if self.take_rename(true, window, cx).is_some() {
12438            return;
12439        }
12440
12441        if self
12442            .context_menu
12443            .borrow_mut()
12444            .as_mut()
12445            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12446            .unwrap_or(false)
12447        {
12448            return;
12449        }
12450
12451        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12452            cx.propagate();
12453            return;
12454        }
12455
12456        let Some(row_count) = self.visible_row_count() else {
12457            return;
12458        };
12459
12460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12461
12462        let effects = if action.center_cursor {
12463            SelectionEffects::scroll(Autoscroll::center())
12464        } else {
12465            SelectionEffects::default()
12466        };
12467
12468        let text_layout_details = &self.text_layout_details(window);
12469
12470        self.change_selections(effects, window, cx, |s| {
12471            s.move_with(|map, selection| {
12472                if !selection.is_empty() {
12473                    selection.goal = SelectionGoal::None;
12474                }
12475                let (cursor, goal) = movement::up_by_rows(
12476                    map,
12477                    selection.end,
12478                    row_count,
12479                    selection.goal,
12480                    false,
12481                    text_layout_details,
12482                );
12483                selection.collapse_to(cursor, goal);
12484            });
12485        });
12486    }
12487
12488    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12490        let text_layout_details = &self.text_layout_details(window);
12491        self.change_selections(Default::default(), window, cx, |s| {
12492            s.move_heads_with(|map, head, goal| {
12493                movement::up(map, head, goal, false, text_layout_details)
12494            })
12495        })
12496    }
12497
12498    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12499        self.take_rename(true, window, cx);
12500
12501        if self.mode.is_single_line() {
12502            cx.propagate();
12503            return;
12504        }
12505
12506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12507
12508        let text_layout_details = &self.text_layout_details(window);
12509        let selection_count = self.selections.count();
12510        let first_selection = self.selections.first_anchor();
12511
12512        self.change_selections(Default::default(), window, cx, |s| {
12513            s.move_with(|map, selection| {
12514                if !selection.is_empty() {
12515                    selection.goal = SelectionGoal::None;
12516                }
12517                let (cursor, goal) = movement::down(
12518                    map,
12519                    selection.end,
12520                    selection.goal,
12521                    false,
12522                    text_layout_details,
12523                );
12524                selection.collapse_to(cursor, goal);
12525            });
12526        });
12527
12528        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12529        {
12530            cx.propagate();
12531        }
12532    }
12533
12534    pub fn select_page_down(
12535        &mut self,
12536        _: &SelectPageDown,
12537        window: &mut Window,
12538        cx: &mut Context<Self>,
12539    ) {
12540        let Some(row_count) = self.visible_row_count() else {
12541            return;
12542        };
12543
12544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12545
12546        let text_layout_details = &self.text_layout_details(window);
12547
12548        self.change_selections(Default::default(), window, cx, |s| {
12549            s.move_heads_with(|map, head, goal| {
12550                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12551            })
12552        })
12553    }
12554
12555    pub fn move_page_down(
12556        &mut self,
12557        action: &MovePageDown,
12558        window: &mut Window,
12559        cx: &mut Context<Self>,
12560    ) {
12561        if self.take_rename(true, window, cx).is_some() {
12562            return;
12563        }
12564
12565        if self
12566            .context_menu
12567            .borrow_mut()
12568            .as_mut()
12569            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12570            .unwrap_or(false)
12571        {
12572            return;
12573        }
12574
12575        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12576            cx.propagate();
12577            return;
12578        }
12579
12580        let Some(row_count) = self.visible_row_count() else {
12581            return;
12582        };
12583
12584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12585
12586        let effects = if action.center_cursor {
12587            SelectionEffects::scroll(Autoscroll::center())
12588        } else {
12589            SelectionEffects::default()
12590        };
12591
12592        let text_layout_details = &self.text_layout_details(window);
12593        self.change_selections(effects, window, cx, |s| {
12594            s.move_with(|map, selection| {
12595                if !selection.is_empty() {
12596                    selection.goal = SelectionGoal::None;
12597                }
12598                let (cursor, goal) = movement::down_by_rows(
12599                    map,
12600                    selection.end,
12601                    row_count,
12602                    selection.goal,
12603                    false,
12604                    text_layout_details,
12605                );
12606                selection.collapse_to(cursor, goal);
12607            });
12608        });
12609    }
12610
12611    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12613        let text_layout_details = &self.text_layout_details(window);
12614        self.change_selections(Default::default(), window, cx, |s| {
12615            s.move_heads_with(|map, head, goal| {
12616                movement::down(map, head, goal, false, text_layout_details)
12617            })
12618        });
12619    }
12620
12621    pub fn context_menu_first(
12622        &mut self,
12623        _: &ContextMenuFirst,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12628            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12629        }
12630    }
12631
12632    pub fn context_menu_prev(
12633        &mut self,
12634        _: &ContextMenuPrevious,
12635        window: &mut Window,
12636        cx: &mut Context<Self>,
12637    ) {
12638        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12639            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12640        }
12641    }
12642
12643    pub fn context_menu_next(
12644        &mut self,
12645        _: &ContextMenuNext,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) {
12649        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12650            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12651        }
12652    }
12653
12654    pub fn context_menu_last(
12655        &mut self,
12656        _: &ContextMenuLast,
12657        window: &mut Window,
12658        cx: &mut Context<Self>,
12659    ) {
12660        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12661            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12662        }
12663    }
12664
12665    pub fn signature_help_prev(
12666        &mut self,
12667        _: &SignatureHelpPrevious,
12668        _: &mut Window,
12669        cx: &mut Context<Self>,
12670    ) {
12671        if let Some(popover) = self.signature_help_state.popover_mut() {
12672            if popover.current_signature == 0 {
12673                popover.current_signature = popover.signatures.len() - 1;
12674            } else {
12675                popover.current_signature -= 1;
12676            }
12677            cx.notify();
12678        }
12679    }
12680
12681    pub fn signature_help_next(
12682        &mut self,
12683        _: &SignatureHelpNext,
12684        _: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        if let Some(popover) = self.signature_help_state.popover_mut() {
12688            if popover.current_signature + 1 == popover.signatures.len() {
12689                popover.current_signature = 0;
12690            } else {
12691                popover.current_signature += 1;
12692            }
12693            cx.notify();
12694        }
12695    }
12696
12697    pub fn move_to_previous_word_start(
12698        &mut self,
12699        _: &MoveToPreviousWordStart,
12700        window: &mut Window,
12701        cx: &mut Context<Self>,
12702    ) {
12703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12704        self.change_selections(Default::default(), window, cx, |s| {
12705            s.move_cursors_with(|map, head, _| {
12706                (
12707                    movement::previous_word_start(map, head),
12708                    SelectionGoal::None,
12709                )
12710            });
12711        })
12712    }
12713
12714    pub fn move_to_previous_subword_start(
12715        &mut self,
12716        _: &MoveToPreviousSubwordStart,
12717        window: &mut Window,
12718        cx: &mut Context<Self>,
12719    ) {
12720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12721        self.change_selections(Default::default(), window, cx, |s| {
12722            s.move_cursors_with(|map, head, _| {
12723                (
12724                    movement::previous_subword_start(map, head),
12725                    SelectionGoal::None,
12726                )
12727            });
12728        })
12729    }
12730
12731    pub fn select_to_previous_word_start(
12732        &mut self,
12733        _: &SelectToPreviousWordStart,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12738        self.change_selections(Default::default(), window, cx, |s| {
12739            s.move_heads_with(|map, head, _| {
12740                (
12741                    movement::previous_word_start(map, head),
12742                    SelectionGoal::None,
12743                )
12744            });
12745        })
12746    }
12747
12748    pub fn select_to_previous_subword_start(
12749        &mut self,
12750        _: &SelectToPreviousSubwordStart,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12755        self.change_selections(Default::default(), window, cx, |s| {
12756            s.move_heads_with(|map, head, _| {
12757                (
12758                    movement::previous_subword_start(map, head),
12759                    SelectionGoal::None,
12760                )
12761            });
12762        })
12763    }
12764
12765    pub fn delete_to_previous_word_start(
12766        &mut self,
12767        action: &DeleteToPreviousWordStart,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) {
12771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12772        self.transact(window, cx, |this, window, cx| {
12773            this.select_autoclose_pair(window, cx);
12774            this.change_selections(Default::default(), window, cx, |s| {
12775                s.move_with(|map, selection| {
12776                    if selection.is_empty() {
12777                        let cursor = if action.ignore_newlines {
12778                            movement::previous_word_start(map, selection.head())
12779                        } else {
12780                            movement::previous_word_start_or_newline(map, selection.head())
12781                        };
12782                        selection.set_head(cursor, SelectionGoal::None);
12783                    }
12784                });
12785            });
12786            this.insert("", window, cx);
12787        });
12788    }
12789
12790    pub fn delete_to_previous_subword_start(
12791        &mut self,
12792        _: &DeleteToPreviousSubwordStart,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) {
12796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12797        self.transact(window, cx, |this, window, cx| {
12798            this.select_autoclose_pair(window, cx);
12799            this.change_selections(Default::default(), window, cx, |s| {
12800                s.move_with(|map, selection| {
12801                    if selection.is_empty() {
12802                        let cursor = movement::previous_subword_start(map, selection.head());
12803                        selection.set_head(cursor, SelectionGoal::None);
12804                    }
12805                });
12806            });
12807            this.insert("", window, cx);
12808        });
12809    }
12810
12811    pub fn move_to_next_word_end(
12812        &mut self,
12813        _: &MoveToNextWordEnd,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12818        self.change_selections(Default::default(), window, cx, |s| {
12819            s.move_cursors_with(|map, head, _| {
12820                (movement::next_word_end(map, head), SelectionGoal::None)
12821            });
12822        })
12823    }
12824
12825    pub fn move_to_next_subword_end(
12826        &mut self,
12827        _: &MoveToNextSubwordEnd,
12828        window: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832        self.change_selections(Default::default(), window, cx, |s| {
12833            s.move_cursors_with(|map, head, _| {
12834                (movement::next_subword_end(map, head), SelectionGoal::None)
12835            });
12836        })
12837    }
12838
12839    pub fn select_to_next_word_end(
12840        &mut self,
12841        _: &SelectToNextWordEnd,
12842        window: &mut Window,
12843        cx: &mut Context<Self>,
12844    ) {
12845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12846        self.change_selections(Default::default(), window, cx, |s| {
12847            s.move_heads_with(|map, head, _| {
12848                (movement::next_word_end(map, head), SelectionGoal::None)
12849            });
12850        })
12851    }
12852
12853    pub fn select_to_next_subword_end(
12854        &mut self,
12855        _: &SelectToNextSubwordEnd,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12860        self.change_selections(Default::default(), window, cx, |s| {
12861            s.move_heads_with(|map, head, _| {
12862                (movement::next_subword_end(map, head), SelectionGoal::None)
12863            });
12864        })
12865    }
12866
12867    pub fn delete_to_next_word_end(
12868        &mut self,
12869        action: &DeleteToNextWordEnd,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12874        self.transact(window, cx, |this, window, cx| {
12875            this.change_selections(Default::default(), window, cx, |s| {
12876                s.move_with(|map, selection| {
12877                    if selection.is_empty() {
12878                        let cursor = if action.ignore_newlines {
12879                            movement::next_word_end(map, selection.head())
12880                        } else {
12881                            movement::next_word_end_or_newline(map, selection.head())
12882                        };
12883                        selection.set_head(cursor, SelectionGoal::None);
12884                    }
12885                });
12886            });
12887            this.insert("", window, cx);
12888        });
12889    }
12890
12891    pub fn delete_to_next_subword_end(
12892        &mut self,
12893        _: &DeleteToNextSubwordEnd,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12898        self.transact(window, cx, |this, window, cx| {
12899            this.change_selections(Default::default(), window, cx, |s| {
12900                s.move_with(|map, selection| {
12901                    if selection.is_empty() {
12902                        let cursor = movement::next_subword_end(map, selection.head());
12903                        selection.set_head(cursor, SelectionGoal::None);
12904                    }
12905                });
12906            });
12907            this.insert("", window, cx);
12908        });
12909    }
12910
12911    pub fn move_to_beginning_of_line(
12912        &mut self,
12913        action: &MoveToBeginningOfLine,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918        self.change_selections(Default::default(), window, cx, |s| {
12919            s.move_cursors_with(|map, head, _| {
12920                (
12921                    movement::indented_line_beginning(
12922                        map,
12923                        head,
12924                        action.stop_at_soft_wraps,
12925                        action.stop_at_indent,
12926                    ),
12927                    SelectionGoal::None,
12928                )
12929            });
12930        })
12931    }
12932
12933    pub fn select_to_beginning_of_line(
12934        &mut self,
12935        action: &SelectToBeginningOfLine,
12936        window: &mut Window,
12937        cx: &mut Context<Self>,
12938    ) {
12939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12940        self.change_selections(Default::default(), window, cx, |s| {
12941            s.move_heads_with(|map, head, _| {
12942                (
12943                    movement::indented_line_beginning(
12944                        map,
12945                        head,
12946                        action.stop_at_soft_wraps,
12947                        action.stop_at_indent,
12948                    ),
12949                    SelectionGoal::None,
12950                )
12951            });
12952        });
12953    }
12954
12955    pub fn delete_to_beginning_of_line(
12956        &mut self,
12957        action: &DeleteToBeginningOfLine,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12962        self.transact(window, cx, |this, window, cx| {
12963            this.change_selections(Default::default(), window, cx, |s| {
12964                s.move_with(|_, selection| {
12965                    selection.reversed = true;
12966                });
12967            });
12968
12969            this.select_to_beginning_of_line(
12970                &SelectToBeginningOfLine {
12971                    stop_at_soft_wraps: false,
12972                    stop_at_indent: action.stop_at_indent,
12973                },
12974                window,
12975                cx,
12976            );
12977            this.backspace(&Backspace, window, cx);
12978        });
12979    }
12980
12981    pub fn move_to_end_of_line(
12982        &mut self,
12983        action: &MoveToEndOfLine,
12984        window: &mut Window,
12985        cx: &mut Context<Self>,
12986    ) {
12987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12988        self.change_selections(Default::default(), window, cx, |s| {
12989            s.move_cursors_with(|map, head, _| {
12990                (
12991                    movement::line_end(map, head, action.stop_at_soft_wraps),
12992                    SelectionGoal::None,
12993                )
12994            });
12995        })
12996    }
12997
12998    pub fn select_to_end_of_line(
12999        &mut self,
13000        action: &SelectToEndOfLine,
13001        window: &mut Window,
13002        cx: &mut Context<Self>,
13003    ) {
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13005        self.change_selections(Default::default(), window, cx, |s| {
13006            s.move_heads_with(|map, head, _| {
13007                (
13008                    movement::line_end(map, head, action.stop_at_soft_wraps),
13009                    SelectionGoal::None,
13010                )
13011            });
13012        })
13013    }
13014
13015    pub fn delete_to_end_of_line(
13016        &mut self,
13017        _: &DeleteToEndOfLine,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13022        self.transact(window, cx, |this, window, cx| {
13023            this.select_to_end_of_line(
13024                &SelectToEndOfLine {
13025                    stop_at_soft_wraps: false,
13026                },
13027                window,
13028                cx,
13029            );
13030            this.delete(&Delete, window, cx);
13031        });
13032    }
13033
13034    pub fn cut_to_end_of_line(
13035        &mut self,
13036        _: &CutToEndOfLine,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13041        self.transact(window, cx, |this, window, cx| {
13042            this.select_to_end_of_line(
13043                &SelectToEndOfLine {
13044                    stop_at_soft_wraps: false,
13045                },
13046                window,
13047                cx,
13048            );
13049            this.cut(&Cut, window, cx);
13050        });
13051    }
13052
13053    pub fn move_to_start_of_paragraph(
13054        &mut self,
13055        _: &MoveToStartOfParagraph,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) {
13059        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13060            cx.propagate();
13061            return;
13062        }
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064        self.change_selections(Default::default(), window, cx, |s| {
13065            s.move_with(|map, selection| {
13066                selection.collapse_to(
13067                    movement::start_of_paragraph(map, selection.head(), 1),
13068                    SelectionGoal::None,
13069                )
13070            });
13071        })
13072    }
13073
13074    pub fn move_to_end_of_paragraph(
13075        &mut self,
13076        _: &MoveToEndOfParagraph,
13077        window: &mut Window,
13078        cx: &mut Context<Self>,
13079    ) {
13080        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13081            cx.propagate();
13082            return;
13083        }
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        self.change_selections(Default::default(), window, cx, |s| {
13086            s.move_with(|map, selection| {
13087                selection.collapse_to(
13088                    movement::end_of_paragraph(map, selection.head(), 1),
13089                    SelectionGoal::None,
13090                )
13091            });
13092        })
13093    }
13094
13095    pub fn select_to_start_of_paragraph(
13096        &mut self,
13097        _: &SelectToStartOfParagraph,
13098        window: &mut Window,
13099        cx: &mut Context<Self>,
13100    ) {
13101        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13102            cx.propagate();
13103            return;
13104        }
13105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13106        self.change_selections(Default::default(), window, cx, |s| {
13107            s.move_heads_with(|map, head, _| {
13108                (
13109                    movement::start_of_paragraph(map, head, 1),
13110                    SelectionGoal::None,
13111                )
13112            });
13113        })
13114    }
13115
13116    pub fn select_to_end_of_paragraph(
13117        &mut self,
13118        _: &SelectToEndOfParagraph,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13123            cx.propagate();
13124            return;
13125        }
13126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13127        self.change_selections(Default::default(), window, cx, |s| {
13128            s.move_heads_with(|map, head, _| {
13129                (
13130                    movement::end_of_paragraph(map, head, 1),
13131                    SelectionGoal::None,
13132                )
13133            });
13134        })
13135    }
13136
13137    pub fn move_to_start_of_excerpt(
13138        &mut self,
13139        _: &MoveToStartOfExcerpt,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13144            cx.propagate();
13145            return;
13146        }
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148        self.change_selections(Default::default(), window, cx, |s| {
13149            s.move_with(|map, selection| {
13150                selection.collapse_to(
13151                    movement::start_of_excerpt(
13152                        map,
13153                        selection.head(),
13154                        workspace::searchable::Direction::Prev,
13155                    ),
13156                    SelectionGoal::None,
13157                )
13158            });
13159        })
13160    }
13161
13162    pub fn move_to_start_of_next_excerpt(
13163        &mut self,
13164        _: &MoveToStartOfNextExcerpt,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13169            cx.propagate();
13170            return;
13171        }
13172
13173        self.change_selections(Default::default(), window, cx, |s| {
13174            s.move_with(|map, selection| {
13175                selection.collapse_to(
13176                    movement::start_of_excerpt(
13177                        map,
13178                        selection.head(),
13179                        workspace::searchable::Direction::Next,
13180                    ),
13181                    SelectionGoal::None,
13182                )
13183            });
13184        })
13185    }
13186
13187    pub fn move_to_end_of_excerpt(
13188        &mut self,
13189        _: &MoveToEndOfExcerpt,
13190        window: &mut Window,
13191        cx: &mut Context<Self>,
13192    ) {
13193        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13194            cx.propagate();
13195            return;
13196        }
13197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13198        self.change_selections(Default::default(), window, cx, |s| {
13199            s.move_with(|map, selection| {
13200                selection.collapse_to(
13201                    movement::end_of_excerpt(
13202                        map,
13203                        selection.head(),
13204                        workspace::searchable::Direction::Next,
13205                    ),
13206                    SelectionGoal::None,
13207                )
13208            });
13209        })
13210    }
13211
13212    pub fn move_to_end_of_previous_excerpt(
13213        &mut self,
13214        _: &MoveToEndOfPreviousExcerpt,
13215        window: &mut Window,
13216        cx: &mut Context<Self>,
13217    ) {
13218        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13219            cx.propagate();
13220            return;
13221        }
13222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13223        self.change_selections(Default::default(), window, cx, |s| {
13224            s.move_with(|map, selection| {
13225                selection.collapse_to(
13226                    movement::end_of_excerpt(
13227                        map,
13228                        selection.head(),
13229                        workspace::searchable::Direction::Prev,
13230                    ),
13231                    SelectionGoal::None,
13232                )
13233            });
13234        })
13235    }
13236
13237    pub fn select_to_start_of_excerpt(
13238        &mut self,
13239        _: &SelectToStartOfExcerpt,
13240        window: &mut Window,
13241        cx: &mut Context<Self>,
13242    ) {
13243        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13244            cx.propagate();
13245            return;
13246        }
13247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13248        self.change_selections(Default::default(), window, cx, |s| {
13249            s.move_heads_with(|map, head, _| {
13250                (
13251                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13252                    SelectionGoal::None,
13253                )
13254            });
13255        })
13256    }
13257
13258    pub fn select_to_start_of_next_excerpt(
13259        &mut self,
13260        _: &SelectToStartOfNextExcerpt,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13265            cx.propagate();
13266            return;
13267        }
13268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13269        self.change_selections(Default::default(), window, cx, |s| {
13270            s.move_heads_with(|map, head, _| {
13271                (
13272                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13273                    SelectionGoal::None,
13274                )
13275            });
13276        })
13277    }
13278
13279    pub fn select_to_end_of_excerpt(
13280        &mut self,
13281        _: &SelectToEndOfExcerpt,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13286            cx.propagate();
13287            return;
13288        }
13289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13290        self.change_selections(Default::default(), window, cx, |s| {
13291            s.move_heads_with(|map, head, _| {
13292                (
13293                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13294                    SelectionGoal::None,
13295                )
13296            });
13297        })
13298    }
13299
13300    pub fn select_to_end_of_previous_excerpt(
13301        &mut self,
13302        _: &SelectToEndOfPreviousExcerpt,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13307            cx.propagate();
13308            return;
13309        }
13310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13311        self.change_selections(Default::default(), window, cx, |s| {
13312            s.move_heads_with(|map, head, _| {
13313                (
13314                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13315                    SelectionGoal::None,
13316                )
13317            });
13318        })
13319    }
13320
13321    pub fn move_to_beginning(
13322        &mut self,
13323        _: &MoveToBeginning,
13324        window: &mut Window,
13325        cx: &mut Context<Self>,
13326    ) {
13327        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13328            cx.propagate();
13329            return;
13330        }
13331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13332        self.change_selections(Default::default(), window, cx, |s| {
13333            s.select_ranges(vec![0..0]);
13334        });
13335    }
13336
13337    pub fn select_to_beginning(
13338        &mut self,
13339        _: &SelectToBeginning,
13340        window: &mut Window,
13341        cx: &mut Context<Self>,
13342    ) {
13343        let mut selection = self.selections.last::<Point>(cx);
13344        selection.set_head(Point::zero(), SelectionGoal::None);
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.select(vec![selection]);
13348        });
13349    }
13350
13351    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13352        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13353            cx.propagate();
13354            return;
13355        }
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        let cursor = self.buffer.read(cx).read(cx).len();
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.select_ranges(vec![cursor..cursor])
13360        });
13361    }
13362
13363    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13364        self.nav_history = nav_history;
13365    }
13366
13367    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13368        self.nav_history.as_ref()
13369    }
13370
13371    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13372        self.push_to_nav_history(
13373            self.selections.newest_anchor().head(),
13374            None,
13375            false,
13376            true,
13377            cx,
13378        );
13379    }
13380
13381    fn push_to_nav_history(
13382        &mut self,
13383        cursor_anchor: Anchor,
13384        new_position: Option<Point>,
13385        is_deactivate: bool,
13386        always: bool,
13387        cx: &mut Context<Self>,
13388    ) {
13389        if let Some(nav_history) = self.nav_history.as_mut() {
13390            let buffer = self.buffer.read(cx).read(cx);
13391            let cursor_position = cursor_anchor.to_point(&buffer);
13392            let scroll_state = self.scroll_manager.anchor();
13393            let scroll_top_row = scroll_state.top_row(&buffer);
13394            drop(buffer);
13395
13396            if let Some(new_position) = new_position {
13397                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13398                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13399                    return;
13400                }
13401            }
13402
13403            nav_history.push(
13404                Some(NavigationData {
13405                    cursor_anchor,
13406                    cursor_position,
13407                    scroll_anchor: scroll_state,
13408                    scroll_top_row,
13409                }),
13410                cx,
13411            );
13412            cx.emit(EditorEvent::PushedToNavHistory {
13413                anchor: cursor_anchor,
13414                is_deactivate,
13415            })
13416        }
13417    }
13418
13419    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13421        let buffer = self.buffer.read(cx).snapshot(cx);
13422        let mut selection = self.selections.first::<usize>(cx);
13423        selection.set_head(buffer.len(), SelectionGoal::None);
13424        self.change_selections(Default::default(), window, cx, |s| {
13425            s.select(vec![selection]);
13426        });
13427    }
13428
13429    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13431        let end = self.buffer.read(cx).read(cx).len();
13432        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13433            s.select_ranges(vec![0..end]);
13434        });
13435    }
13436
13437    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13440        let mut selections = self.selections.all::<Point>(cx);
13441        let max_point = display_map.buffer_snapshot.max_point();
13442        for selection in &mut selections {
13443            let rows = selection.spanned_rows(true, &display_map);
13444            selection.start = Point::new(rows.start.0, 0);
13445            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13446            selection.reversed = false;
13447        }
13448        self.change_selections(Default::default(), window, cx, |s| {
13449            s.select(selections);
13450        });
13451    }
13452
13453    pub fn split_selection_into_lines(
13454        &mut self,
13455        _: &SplitSelectionIntoLines,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        let selections = self
13460            .selections
13461            .all::<Point>(cx)
13462            .into_iter()
13463            .map(|selection| selection.start..selection.end)
13464            .collect::<Vec<_>>();
13465        self.unfold_ranges(&selections, true, true, cx);
13466
13467        let mut new_selection_ranges = Vec::new();
13468        {
13469            let buffer = self.buffer.read(cx).read(cx);
13470            for selection in selections {
13471                for row in selection.start.row..selection.end.row {
13472                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13473                    new_selection_ranges.push(cursor..cursor);
13474                }
13475
13476                let is_multiline_selection = selection.start.row != selection.end.row;
13477                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13478                // so this action feels more ergonomic when paired with other selection operations
13479                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13480                if !should_skip_last {
13481                    new_selection_ranges.push(selection.end..selection.end);
13482                }
13483            }
13484        }
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.select_ranges(new_selection_ranges);
13487        });
13488    }
13489
13490    pub fn add_selection_above(
13491        &mut self,
13492        _: &AddSelectionAbove,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        self.add_selection(true, window, cx);
13497    }
13498
13499    pub fn add_selection_below(
13500        &mut self,
13501        _: &AddSelectionBelow,
13502        window: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) {
13505        self.add_selection(false, window, cx);
13506    }
13507
13508    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13510
13511        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13512        let all_selections = self.selections.all::<Point>(cx);
13513        let text_layout_details = self.text_layout_details(window);
13514
13515        let (mut columnar_selections, new_selections_to_columnarize) = {
13516            if let Some(state) = self.add_selections_state.as_ref() {
13517                let columnar_selection_ids: HashSet<_> = state
13518                    .groups
13519                    .iter()
13520                    .flat_map(|group| group.stack.iter())
13521                    .copied()
13522                    .collect();
13523
13524                all_selections
13525                    .into_iter()
13526                    .partition(|s| columnar_selection_ids.contains(&s.id))
13527            } else {
13528                (Vec::new(), all_selections)
13529            }
13530        };
13531
13532        let mut state = self
13533            .add_selections_state
13534            .take()
13535            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13536
13537        for selection in new_selections_to_columnarize {
13538            let range = selection.display_range(&display_map).sorted();
13539            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13540            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13541            let positions = start_x.min(end_x)..start_x.max(end_x);
13542            let mut stack = Vec::new();
13543            for row in range.start.row().0..=range.end.row().0 {
13544                if let Some(selection) = self.selections.build_columnar_selection(
13545                    &display_map,
13546                    DisplayRow(row),
13547                    &positions,
13548                    selection.reversed,
13549                    &text_layout_details,
13550                ) {
13551                    stack.push(selection.id);
13552                    columnar_selections.push(selection);
13553                }
13554            }
13555            if !stack.is_empty() {
13556                if above {
13557                    stack.reverse();
13558                }
13559                state.groups.push(AddSelectionsGroup { above, stack });
13560            }
13561        }
13562
13563        let mut final_selections = Vec::new();
13564        let end_row = if above {
13565            DisplayRow(0)
13566        } else {
13567            display_map.max_point().row()
13568        };
13569
13570        let mut last_added_item_per_group = HashMap::default();
13571        for group in state.groups.iter_mut() {
13572            if let Some(last_id) = group.stack.last() {
13573                last_added_item_per_group.insert(*last_id, group);
13574            }
13575        }
13576
13577        for selection in columnar_selections {
13578            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13579                if above == group.above {
13580                    let range = selection.display_range(&display_map).sorted();
13581                    debug_assert_eq!(range.start.row(), range.end.row());
13582                    let mut row = range.start.row();
13583                    let positions =
13584                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13585                            px(start)..px(end)
13586                        } else {
13587                            let start_x =
13588                                display_map.x_for_display_point(range.start, &text_layout_details);
13589                            let end_x =
13590                                display_map.x_for_display_point(range.end, &text_layout_details);
13591                            start_x.min(end_x)..start_x.max(end_x)
13592                        };
13593
13594                    let mut maybe_new_selection = None;
13595                    while row != end_row {
13596                        if above {
13597                            row.0 -= 1;
13598                        } else {
13599                            row.0 += 1;
13600                        }
13601                        if let Some(new_selection) = self.selections.build_columnar_selection(
13602                            &display_map,
13603                            row,
13604                            &positions,
13605                            selection.reversed,
13606                            &text_layout_details,
13607                        ) {
13608                            maybe_new_selection = Some(new_selection);
13609                            break;
13610                        }
13611                    }
13612
13613                    if let Some(new_selection) = maybe_new_selection {
13614                        group.stack.push(new_selection.id);
13615                        if above {
13616                            final_selections.push(new_selection);
13617                            final_selections.push(selection);
13618                        } else {
13619                            final_selections.push(selection);
13620                            final_selections.push(new_selection);
13621                        }
13622                    } else {
13623                        final_selections.push(selection);
13624                    }
13625                } else {
13626                    group.stack.pop();
13627                }
13628            } else {
13629                final_selections.push(selection);
13630            }
13631        }
13632
13633        self.change_selections(Default::default(), window, cx, |s| {
13634            s.select(final_selections);
13635        });
13636
13637        let final_selection_ids: HashSet<_> = self
13638            .selections
13639            .all::<Point>(cx)
13640            .iter()
13641            .map(|s| s.id)
13642            .collect();
13643        state.groups.retain_mut(|group| {
13644            // selections might get merged above so we remove invalid items from stacks
13645            group.stack.retain(|id| final_selection_ids.contains(id));
13646
13647            // single selection in stack can be treated as initial state
13648            group.stack.len() > 1
13649        });
13650
13651        if !state.groups.is_empty() {
13652            self.add_selections_state = Some(state);
13653        }
13654    }
13655
13656    fn select_match_ranges(
13657        &mut self,
13658        range: Range<usize>,
13659        reversed: bool,
13660        replace_newest: bool,
13661        auto_scroll: Option<Autoscroll>,
13662        window: &mut Window,
13663        cx: &mut Context<Editor>,
13664    ) {
13665        self.unfold_ranges(
13666            std::slice::from_ref(&range),
13667            false,
13668            auto_scroll.is_some(),
13669            cx,
13670        );
13671        let effects = if let Some(scroll) = auto_scroll {
13672            SelectionEffects::scroll(scroll)
13673        } else {
13674            SelectionEffects::no_scroll()
13675        };
13676        self.change_selections(effects, window, cx, |s| {
13677            if replace_newest {
13678                s.delete(s.newest_anchor().id);
13679            }
13680            if reversed {
13681                s.insert_range(range.end..range.start);
13682            } else {
13683                s.insert_range(range);
13684            }
13685        });
13686    }
13687
13688    pub fn select_next_match_internal(
13689        &mut self,
13690        display_map: &DisplaySnapshot,
13691        replace_newest: bool,
13692        autoscroll: Option<Autoscroll>,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) -> Result<()> {
13696        let buffer = &display_map.buffer_snapshot;
13697        let mut selections = self.selections.all::<usize>(cx);
13698        if let Some(mut select_next_state) = self.select_next_state.take() {
13699            let query = &select_next_state.query;
13700            if !select_next_state.done {
13701                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13702                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13703                let mut next_selected_range = None;
13704
13705                let bytes_after_last_selection =
13706                    buffer.bytes_in_range(last_selection.end..buffer.len());
13707                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13708                let query_matches = query
13709                    .stream_find_iter(bytes_after_last_selection)
13710                    .map(|result| (last_selection.end, result))
13711                    .chain(
13712                        query
13713                            .stream_find_iter(bytes_before_first_selection)
13714                            .map(|result| (0, result)),
13715                    );
13716
13717                for (start_offset, query_match) in query_matches {
13718                    let query_match = query_match.unwrap(); // can only fail due to I/O
13719                    let offset_range =
13720                        start_offset + query_match.start()..start_offset + query_match.end();
13721
13722                    if !select_next_state.wordwise
13723                        || (!buffer.is_inside_word(offset_range.start, false)
13724                            && !buffer.is_inside_word(offset_range.end, false))
13725                    {
13726                        // TODO: This is n^2, because we might check all the selections
13727                        if !selections
13728                            .iter()
13729                            .any(|selection| selection.range().overlaps(&offset_range))
13730                        {
13731                            next_selected_range = Some(offset_range);
13732                            break;
13733                        }
13734                    }
13735                }
13736
13737                if let Some(next_selected_range) = next_selected_range {
13738                    self.select_match_ranges(
13739                        next_selected_range,
13740                        last_selection.reversed,
13741                        replace_newest,
13742                        autoscroll,
13743                        window,
13744                        cx,
13745                    );
13746                } else {
13747                    select_next_state.done = true;
13748                }
13749            }
13750
13751            self.select_next_state = Some(select_next_state);
13752        } else {
13753            let mut only_carets = true;
13754            let mut same_text_selected = true;
13755            let mut selected_text = None;
13756
13757            let mut selections_iter = selections.iter().peekable();
13758            while let Some(selection) = selections_iter.next() {
13759                if selection.start != selection.end {
13760                    only_carets = false;
13761                }
13762
13763                if same_text_selected {
13764                    if selected_text.is_none() {
13765                        selected_text =
13766                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13767                    }
13768
13769                    if let Some(next_selection) = selections_iter.peek() {
13770                        if next_selection.range().len() == selection.range().len() {
13771                            let next_selected_text = buffer
13772                                .text_for_range(next_selection.range())
13773                                .collect::<String>();
13774                            if Some(next_selected_text) != selected_text {
13775                                same_text_selected = false;
13776                                selected_text = None;
13777                            }
13778                        } else {
13779                            same_text_selected = false;
13780                            selected_text = None;
13781                        }
13782                    }
13783                }
13784            }
13785
13786            if only_carets {
13787                for selection in &mut selections {
13788                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13789                    selection.start = word_range.start;
13790                    selection.end = word_range.end;
13791                    selection.goal = SelectionGoal::None;
13792                    selection.reversed = false;
13793                    self.select_match_ranges(
13794                        selection.start..selection.end,
13795                        selection.reversed,
13796                        replace_newest,
13797                        autoscroll,
13798                        window,
13799                        cx,
13800                    );
13801                }
13802
13803                if selections.len() == 1 {
13804                    let selection = selections
13805                        .last()
13806                        .expect("ensured that there's only one selection");
13807                    let query = buffer
13808                        .text_for_range(selection.start..selection.end)
13809                        .collect::<String>();
13810                    let is_empty = query.is_empty();
13811                    let select_state = SelectNextState {
13812                        query: AhoCorasick::new(&[query])?,
13813                        wordwise: true,
13814                        done: is_empty,
13815                    };
13816                    self.select_next_state = Some(select_state);
13817                } else {
13818                    self.select_next_state = None;
13819                }
13820            } else if let Some(selected_text) = selected_text {
13821                self.select_next_state = Some(SelectNextState {
13822                    query: AhoCorasick::new(&[selected_text])?,
13823                    wordwise: false,
13824                    done: false,
13825                });
13826                self.select_next_match_internal(
13827                    display_map,
13828                    replace_newest,
13829                    autoscroll,
13830                    window,
13831                    cx,
13832                )?;
13833            }
13834        }
13835        Ok(())
13836    }
13837
13838    pub fn select_all_matches(
13839        &mut self,
13840        _action: &SelectAllMatches,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) -> Result<()> {
13844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13845
13846        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13847
13848        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13849        let Some(select_next_state) = self.select_next_state.as_mut() else {
13850            return Ok(());
13851        };
13852        if select_next_state.done {
13853            return Ok(());
13854        }
13855
13856        let mut new_selections = Vec::new();
13857
13858        let reversed = self.selections.oldest::<usize>(cx).reversed;
13859        let buffer = &display_map.buffer_snapshot;
13860        let query_matches = select_next_state
13861            .query
13862            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13863
13864        for query_match in query_matches.into_iter() {
13865            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13866            let offset_range = if reversed {
13867                query_match.end()..query_match.start()
13868            } else {
13869                query_match.start()..query_match.end()
13870            };
13871
13872            if !select_next_state.wordwise
13873                || (!buffer.is_inside_word(offset_range.start, false)
13874                    && !buffer.is_inside_word(offset_range.end, false))
13875            {
13876                new_selections.push(offset_range.start..offset_range.end);
13877            }
13878        }
13879
13880        select_next_state.done = true;
13881
13882        if new_selections.is_empty() {
13883            log::error!("bug: new_selections is empty in select_all_matches");
13884            return Ok(());
13885        }
13886
13887        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13889            selections.select_ranges(new_selections)
13890        });
13891
13892        Ok(())
13893    }
13894
13895    pub fn select_next(
13896        &mut self,
13897        action: &SelectNext,
13898        window: &mut Window,
13899        cx: &mut Context<Self>,
13900    ) -> Result<()> {
13901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13903        self.select_next_match_internal(
13904            &display_map,
13905            action.replace_newest,
13906            Some(Autoscroll::newest()),
13907            window,
13908            cx,
13909        )?;
13910        Ok(())
13911    }
13912
13913    pub fn select_previous(
13914        &mut self,
13915        action: &SelectPrevious,
13916        window: &mut Window,
13917        cx: &mut Context<Self>,
13918    ) -> Result<()> {
13919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13921        let buffer = &display_map.buffer_snapshot;
13922        let mut selections = self.selections.all::<usize>(cx);
13923        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13924            let query = &select_prev_state.query;
13925            if !select_prev_state.done {
13926                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13927                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13928                let mut next_selected_range = None;
13929                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13930                let bytes_before_last_selection =
13931                    buffer.reversed_bytes_in_range(0..last_selection.start);
13932                let bytes_after_first_selection =
13933                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13934                let query_matches = query
13935                    .stream_find_iter(bytes_before_last_selection)
13936                    .map(|result| (last_selection.start, result))
13937                    .chain(
13938                        query
13939                            .stream_find_iter(bytes_after_first_selection)
13940                            .map(|result| (buffer.len(), result)),
13941                    );
13942                for (end_offset, query_match) in query_matches {
13943                    let query_match = query_match.unwrap(); // can only fail due to I/O
13944                    let offset_range =
13945                        end_offset - query_match.end()..end_offset - query_match.start();
13946
13947                    if !select_prev_state.wordwise
13948                        || (!buffer.is_inside_word(offset_range.start, false)
13949                            && !buffer.is_inside_word(offset_range.end, false))
13950                    {
13951                        next_selected_range = Some(offset_range);
13952                        break;
13953                    }
13954                }
13955
13956                if let Some(next_selected_range) = next_selected_range {
13957                    self.select_match_ranges(
13958                        next_selected_range,
13959                        last_selection.reversed,
13960                        action.replace_newest,
13961                        Some(Autoscroll::newest()),
13962                        window,
13963                        cx,
13964                    );
13965                } else {
13966                    select_prev_state.done = true;
13967                }
13968            }
13969
13970            self.select_prev_state = Some(select_prev_state);
13971        } else {
13972            let mut only_carets = true;
13973            let mut same_text_selected = true;
13974            let mut selected_text = None;
13975
13976            let mut selections_iter = selections.iter().peekable();
13977            while let Some(selection) = selections_iter.next() {
13978                if selection.start != selection.end {
13979                    only_carets = false;
13980                }
13981
13982                if same_text_selected {
13983                    if selected_text.is_none() {
13984                        selected_text =
13985                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13986                    }
13987
13988                    if let Some(next_selection) = selections_iter.peek() {
13989                        if next_selection.range().len() == selection.range().len() {
13990                            let next_selected_text = buffer
13991                                .text_for_range(next_selection.range())
13992                                .collect::<String>();
13993                            if Some(next_selected_text) != selected_text {
13994                                same_text_selected = false;
13995                                selected_text = None;
13996                            }
13997                        } else {
13998                            same_text_selected = false;
13999                            selected_text = None;
14000                        }
14001                    }
14002                }
14003            }
14004
14005            if only_carets {
14006                for selection in &mut selections {
14007                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14008                    selection.start = word_range.start;
14009                    selection.end = word_range.end;
14010                    selection.goal = SelectionGoal::None;
14011                    selection.reversed = false;
14012                    self.select_match_ranges(
14013                        selection.start..selection.end,
14014                        selection.reversed,
14015                        action.replace_newest,
14016                        Some(Autoscroll::newest()),
14017                        window,
14018                        cx,
14019                    );
14020                }
14021                if selections.len() == 1 {
14022                    let selection = selections
14023                        .last()
14024                        .expect("ensured that there's only one selection");
14025                    let query = buffer
14026                        .text_for_range(selection.start..selection.end)
14027                        .collect::<String>();
14028                    let is_empty = query.is_empty();
14029                    let select_state = SelectNextState {
14030                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14031                        wordwise: true,
14032                        done: is_empty,
14033                    };
14034                    self.select_prev_state = Some(select_state);
14035                } else {
14036                    self.select_prev_state = None;
14037                }
14038            } else if let Some(selected_text) = selected_text {
14039                self.select_prev_state = Some(SelectNextState {
14040                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14041                    wordwise: false,
14042                    done: false,
14043                });
14044                self.select_previous(action, window, cx)?;
14045            }
14046        }
14047        Ok(())
14048    }
14049
14050    pub fn find_next_match(
14051        &mut self,
14052        _: &FindNextMatch,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) -> Result<()> {
14056        let selections = self.selections.disjoint_anchors();
14057        match selections.first() {
14058            Some(first) if selections.len() >= 2 => {
14059                self.change_selections(Default::default(), window, cx, |s| {
14060                    s.select_ranges([first.range()]);
14061                });
14062            }
14063            _ => self.select_next(
14064                &SelectNext {
14065                    replace_newest: true,
14066                },
14067                window,
14068                cx,
14069            )?,
14070        }
14071        Ok(())
14072    }
14073
14074    pub fn find_previous_match(
14075        &mut self,
14076        _: &FindPreviousMatch,
14077        window: &mut Window,
14078        cx: &mut Context<Self>,
14079    ) -> Result<()> {
14080        let selections = self.selections.disjoint_anchors();
14081        match selections.last() {
14082            Some(last) if selections.len() >= 2 => {
14083                self.change_selections(Default::default(), window, cx, |s| {
14084                    s.select_ranges([last.range()]);
14085                });
14086            }
14087            _ => self.select_previous(
14088                &SelectPrevious {
14089                    replace_newest: true,
14090                },
14091                window,
14092                cx,
14093            )?,
14094        }
14095        Ok(())
14096    }
14097
14098    pub fn toggle_comments(
14099        &mut self,
14100        action: &ToggleComments,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        if self.read_only(cx) {
14105            return;
14106        }
14107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14108        let text_layout_details = &self.text_layout_details(window);
14109        self.transact(window, cx, |this, window, cx| {
14110            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14111            let mut edits = Vec::new();
14112            let mut selection_edit_ranges = Vec::new();
14113            let mut last_toggled_row = None;
14114            let snapshot = this.buffer.read(cx).read(cx);
14115            let empty_str: Arc<str> = Arc::default();
14116            let mut suffixes_inserted = Vec::new();
14117            let ignore_indent = action.ignore_indent;
14118
14119            fn comment_prefix_range(
14120                snapshot: &MultiBufferSnapshot,
14121                row: MultiBufferRow,
14122                comment_prefix: &str,
14123                comment_prefix_whitespace: &str,
14124                ignore_indent: bool,
14125            ) -> Range<Point> {
14126                let indent_size = if ignore_indent {
14127                    0
14128                } else {
14129                    snapshot.indent_size_for_line(row).len
14130                };
14131
14132                let start = Point::new(row.0, indent_size);
14133
14134                let mut line_bytes = snapshot
14135                    .bytes_in_range(start..snapshot.max_point())
14136                    .flatten()
14137                    .copied();
14138
14139                // If this line currently begins with the line comment prefix, then record
14140                // the range containing the prefix.
14141                if line_bytes
14142                    .by_ref()
14143                    .take(comment_prefix.len())
14144                    .eq(comment_prefix.bytes())
14145                {
14146                    // Include any whitespace that matches the comment prefix.
14147                    let matching_whitespace_len = line_bytes
14148                        .zip(comment_prefix_whitespace.bytes())
14149                        .take_while(|(a, b)| a == b)
14150                        .count() as u32;
14151                    let end = Point::new(
14152                        start.row,
14153                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14154                    );
14155                    start..end
14156                } else {
14157                    start..start
14158                }
14159            }
14160
14161            fn comment_suffix_range(
14162                snapshot: &MultiBufferSnapshot,
14163                row: MultiBufferRow,
14164                comment_suffix: &str,
14165                comment_suffix_has_leading_space: bool,
14166            ) -> Range<Point> {
14167                let end = Point::new(row.0, snapshot.line_len(row));
14168                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14169
14170                let mut line_end_bytes = snapshot
14171                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14172                    .flatten()
14173                    .copied();
14174
14175                let leading_space_len = if suffix_start_column > 0
14176                    && line_end_bytes.next() == Some(b' ')
14177                    && comment_suffix_has_leading_space
14178                {
14179                    1
14180                } else {
14181                    0
14182                };
14183
14184                // If this line currently begins with the line comment prefix, then record
14185                // the range containing the prefix.
14186                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14187                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14188                    start..end
14189                } else {
14190                    end..end
14191                }
14192            }
14193
14194            // TODO: Handle selections that cross excerpts
14195            for selection in &mut selections {
14196                let start_column = snapshot
14197                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14198                    .len;
14199                let language = if let Some(language) =
14200                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14201                {
14202                    language
14203                } else {
14204                    continue;
14205                };
14206
14207                selection_edit_ranges.clear();
14208
14209                // If multiple selections contain a given row, avoid processing that
14210                // row more than once.
14211                let mut start_row = MultiBufferRow(selection.start.row);
14212                if last_toggled_row == Some(start_row) {
14213                    start_row = start_row.next_row();
14214                }
14215                let end_row =
14216                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14217                        MultiBufferRow(selection.end.row - 1)
14218                    } else {
14219                        MultiBufferRow(selection.end.row)
14220                    };
14221                last_toggled_row = Some(end_row);
14222
14223                if start_row > end_row {
14224                    continue;
14225                }
14226
14227                // If the language has line comments, toggle those.
14228                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14229
14230                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14231                if ignore_indent {
14232                    full_comment_prefixes = full_comment_prefixes
14233                        .into_iter()
14234                        .map(|s| Arc::from(s.trim_end()))
14235                        .collect();
14236                }
14237
14238                if !full_comment_prefixes.is_empty() {
14239                    let first_prefix = full_comment_prefixes
14240                        .first()
14241                        .expect("prefixes is non-empty");
14242                    let prefix_trimmed_lengths = full_comment_prefixes
14243                        .iter()
14244                        .map(|p| p.trim_end_matches(' ').len())
14245                        .collect::<SmallVec<[usize; 4]>>();
14246
14247                    let mut all_selection_lines_are_comments = true;
14248
14249                    for row in start_row.0..=end_row.0 {
14250                        let row = MultiBufferRow(row);
14251                        if start_row < end_row && snapshot.is_line_blank(row) {
14252                            continue;
14253                        }
14254
14255                        let prefix_range = full_comment_prefixes
14256                            .iter()
14257                            .zip(prefix_trimmed_lengths.iter().copied())
14258                            .map(|(prefix, trimmed_prefix_len)| {
14259                                comment_prefix_range(
14260                                    snapshot.deref(),
14261                                    row,
14262                                    &prefix[..trimmed_prefix_len],
14263                                    &prefix[trimmed_prefix_len..],
14264                                    ignore_indent,
14265                                )
14266                            })
14267                            .max_by_key(|range| range.end.column - range.start.column)
14268                            .expect("prefixes is non-empty");
14269
14270                        if prefix_range.is_empty() {
14271                            all_selection_lines_are_comments = false;
14272                        }
14273
14274                        selection_edit_ranges.push(prefix_range);
14275                    }
14276
14277                    if all_selection_lines_are_comments {
14278                        edits.extend(
14279                            selection_edit_ranges
14280                                .iter()
14281                                .cloned()
14282                                .map(|range| (range, empty_str.clone())),
14283                        );
14284                    } else {
14285                        let min_column = selection_edit_ranges
14286                            .iter()
14287                            .map(|range| range.start.column)
14288                            .min()
14289                            .unwrap_or(0);
14290                        edits.extend(selection_edit_ranges.iter().map(|range| {
14291                            let position = Point::new(range.start.row, min_column);
14292                            (position..position, first_prefix.clone())
14293                        }));
14294                    }
14295                } else if let Some((full_comment_prefix, comment_suffix)) =
14296                    language.block_comment_delimiters()
14297                {
14298                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14299                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14300                    let prefix_range = comment_prefix_range(
14301                        snapshot.deref(),
14302                        start_row,
14303                        comment_prefix,
14304                        comment_prefix_whitespace,
14305                        ignore_indent,
14306                    );
14307                    let suffix_range = comment_suffix_range(
14308                        snapshot.deref(),
14309                        end_row,
14310                        comment_suffix.trim_start_matches(' '),
14311                        comment_suffix.starts_with(' '),
14312                    );
14313
14314                    if prefix_range.is_empty() || suffix_range.is_empty() {
14315                        edits.push((
14316                            prefix_range.start..prefix_range.start,
14317                            full_comment_prefix.clone(),
14318                        ));
14319                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14320                        suffixes_inserted.push((end_row, comment_suffix.len()));
14321                    } else {
14322                        edits.push((prefix_range, empty_str.clone()));
14323                        edits.push((suffix_range, empty_str.clone()));
14324                    }
14325                } else {
14326                    continue;
14327                }
14328            }
14329
14330            drop(snapshot);
14331            this.buffer.update(cx, |buffer, cx| {
14332                buffer.edit(edits, None, cx);
14333            });
14334
14335            // Adjust selections so that they end before any comment suffixes that
14336            // were inserted.
14337            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14338            let mut selections = this.selections.all::<Point>(cx);
14339            let snapshot = this.buffer.read(cx).read(cx);
14340            for selection in &mut selections {
14341                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14342                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14343                        Ordering::Less => {
14344                            suffixes_inserted.next();
14345                            continue;
14346                        }
14347                        Ordering::Greater => break,
14348                        Ordering::Equal => {
14349                            if selection.end.column == snapshot.line_len(row) {
14350                                if selection.is_empty() {
14351                                    selection.start.column -= suffix_len as u32;
14352                                }
14353                                selection.end.column -= suffix_len as u32;
14354                            }
14355                            break;
14356                        }
14357                    }
14358                }
14359            }
14360
14361            drop(snapshot);
14362            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14363
14364            let selections = this.selections.all::<Point>(cx);
14365            let selections_on_single_row = selections.windows(2).all(|selections| {
14366                selections[0].start.row == selections[1].start.row
14367                    && selections[0].end.row == selections[1].end.row
14368                    && selections[0].start.row == selections[0].end.row
14369            });
14370            let selections_selecting = selections
14371                .iter()
14372                .any(|selection| selection.start != selection.end);
14373            let advance_downwards = action.advance_downwards
14374                && selections_on_single_row
14375                && !selections_selecting
14376                && !matches!(this.mode, EditorMode::SingleLine { .. });
14377
14378            if advance_downwards {
14379                let snapshot = this.buffer.read(cx).snapshot(cx);
14380
14381                this.change_selections(Default::default(), window, cx, |s| {
14382                    s.move_cursors_with(|display_snapshot, display_point, _| {
14383                        let mut point = display_point.to_point(display_snapshot);
14384                        point.row += 1;
14385                        point = snapshot.clip_point(point, Bias::Left);
14386                        let display_point = point.to_display_point(display_snapshot);
14387                        let goal = SelectionGoal::HorizontalPosition(
14388                            display_snapshot
14389                                .x_for_display_point(display_point, text_layout_details)
14390                                .into(),
14391                        );
14392                        (display_point, goal)
14393                    })
14394                });
14395            }
14396        });
14397    }
14398
14399    pub fn select_enclosing_symbol(
14400        &mut self,
14401        _: &SelectEnclosingSymbol,
14402        window: &mut Window,
14403        cx: &mut Context<Self>,
14404    ) {
14405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14406
14407        let buffer = self.buffer.read(cx).snapshot(cx);
14408        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14409
14410        fn update_selection(
14411            selection: &Selection<usize>,
14412            buffer_snap: &MultiBufferSnapshot,
14413        ) -> Option<Selection<usize>> {
14414            let cursor = selection.head();
14415            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14416            for symbol in symbols.iter().rev() {
14417                let start = symbol.range.start.to_offset(buffer_snap);
14418                let end = symbol.range.end.to_offset(buffer_snap);
14419                let new_range = start..end;
14420                if start < selection.start || end > selection.end {
14421                    return Some(Selection {
14422                        id: selection.id,
14423                        start: new_range.start,
14424                        end: new_range.end,
14425                        goal: SelectionGoal::None,
14426                        reversed: selection.reversed,
14427                    });
14428                }
14429            }
14430            None
14431        }
14432
14433        let mut selected_larger_symbol = false;
14434        let new_selections = old_selections
14435            .iter()
14436            .map(|selection| match update_selection(selection, &buffer) {
14437                Some(new_selection) => {
14438                    if new_selection.range() != selection.range() {
14439                        selected_larger_symbol = true;
14440                    }
14441                    new_selection
14442                }
14443                None => selection.clone(),
14444            })
14445            .collect::<Vec<_>>();
14446
14447        if selected_larger_symbol {
14448            self.change_selections(Default::default(), window, cx, |s| {
14449                s.select(new_selections);
14450            });
14451        }
14452    }
14453
14454    pub fn select_larger_syntax_node(
14455        &mut self,
14456        _: &SelectLargerSyntaxNode,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) {
14460        let Some(visible_row_count) = self.visible_row_count() else {
14461            return;
14462        };
14463        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14464        if old_selections.is_empty() {
14465            return;
14466        }
14467
14468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14469
14470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14471        let buffer = self.buffer.read(cx).snapshot(cx);
14472
14473        let mut selected_larger_node = false;
14474        let mut new_selections = old_selections
14475            .iter()
14476            .map(|selection| {
14477                let old_range = selection.start..selection.end;
14478
14479                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14480                    // manually select word at selection
14481                    if ["string_content", "inline"].contains(&node.kind()) {
14482                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14483                        // ignore if word is already selected
14484                        if !word_range.is_empty() && old_range != word_range {
14485                            let (last_word_range, _) =
14486                                buffer.surrounding_word(old_range.end, false);
14487                            // only select word if start and end point belongs to same word
14488                            if word_range == last_word_range {
14489                                selected_larger_node = true;
14490                                return Selection {
14491                                    id: selection.id,
14492                                    start: word_range.start,
14493                                    end: word_range.end,
14494                                    goal: SelectionGoal::None,
14495                                    reversed: selection.reversed,
14496                                };
14497                            }
14498                        }
14499                    }
14500                }
14501
14502                let mut new_range = old_range.clone();
14503                while let Some((_node, containing_range)) =
14504                    buffer.syntax_ancestor(new_range.clone())
14505                {
14506                    new_range = match containing_range {
14507                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14508                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14509                    };
14510                    if !display_map.intersects_fold(new_range.start)
14511                        && !display_map.intersects_fold(new_range.end)
14512                    {
14513                        break;
14514                    }
14515                }
14516
14517                selected_larger_node |= new_range != old_range;
14518                Selection {
14519                    id: selection.id,
14520                    start: new_range.start,
14521                    end: new_range.end,
14522                    goal: SelectionGoal::None,
14523                    reversed: selection.reversed,
14524                }
14525            })
14526            .collect::<Vec<_>>();
14527
14528        if !selected_larger_node {
14529            return; // don't put this call in the history
14530        }
14531
14532        // scroll based on transformation done to the last selection created by the user
14533        let (last_old, last_new) = old_selections
14534            .last()
14535            .zip(new_selections.last().cloned())
14536            .expect("old_selections isn't empty");
14537
14538        // revert selection
14539        let is_selection_reversed = {
14540            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14541            new_selections.last_mut().expect("checked above").reversed =
14542                should_newest_selection_be_reversed;
14543            should_newest_selection_be_reversed
14544        };
14545
14546        if selected_larger_node {
14547            self.select_syntax_node_history.disable_clearing = true;
14548            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14549                s.select(new_selections.clone());
14550            });
14551            self.select_syntax_node_history.disable_clearing = false;
14552        }
14553
14554        let start_row = last_new.start.to_display_point(&display_map).row().0;
14555        let end_row = last_new.end.to_display_point(&display_map).row().0;
14556        let selection_height = end_row - start_row + 1;
14557        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14558
14559        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14560        let scroll_behavior = if fits_on_the_screen {
14561            self.request_autoscroll(Autoscroll::fit(), cx);
14562            SelectSyntaxNodeScrollBehavior::FitSelection
14563        } else if is_selection_reversed {
14564            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14565            SelectSyntaxNodeScrollBehavior::CursorTop
14566        } else {
14567            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14568            SelectSyntaxNodeScrollBehavior::CursorBottom
14569        };
14570
14571        self.select_syntax_node_history.push((
14572            old_selections,
14573            scroll_behavior,
14574            is_selection_reversed,
14575        ));
14576    }
14577
14578    pub fn select_smaller_syntax_node(
14579        &mut self,
14580        _: &SelectSmallerSyntaxNode,
14581        window: &mut Window,
14582        cx: &mut Context<Self>,
14583    ) {
14584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14585
14586        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14587            self.select_syntax_node_history.pop()
14588        {
14589            if let Some(selection) = selections.last_mut() {
14590                selection.reversed = is_selection_reversed;
14591            }
14592
14593            self.select_syntax_node_history.disable_clearing = true;
14594            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14595                s.select(selections.to_vec());
14596            });
14597            self.select_syntax_node_history.disable_clearing = false;
14598
14599            match scroll_behavior {
14600                SelectSyntaxNodeScrollBehavior::CursorTop => {
14601                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14602                }
14603                SelectSyntaxNodeScrollBehavior::FitSelection => {
14604                    self.request_autoscroll(Autoscroll::fit(), cx);
14605                }
14606                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14607                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14608                }
14609            }
14610        }
14611    }
14612
14613    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14614        if !EditorSettings::get_global(cx).gutter.runnables {
14615            self.clear_tasks();
14616            return Task::ready(());
14617        }
14618        let project = self.project.as_ref().map(Entity::downgrade);
14619        let task_sources = self.lsp_task_sources(cx);
14620        let multi_buffer = self.buffer.downgrade();
14621        cx.spawn_in(window, async move |editor, cx| {
14622            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14623            let Some(project) = project.and_then(|p| p.upgrade()) else {
14624                return;
14625            };
14626            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14627                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14628            }) else {
14629                return;
14630            };
14631
14632            let hide_runnables = project
14633                .update(cx, |project, cx| {
14634                    // Do not display any test indicators in non-dev server remote projects.
14635                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14636                })
14637                .unwrap_or(true);
14638            if hide_runnables {
14639                return;
14640            }
14641            let new_rows =
14642                cx.background_spawn({
14643                    let snapshot = display_snapshot.clone();
14644                    async move {
14645                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14646                    }
14647                })
14648                    .await;
14649            let Ok(lsp_tasks) =
14650                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14651            else {
14652                return;
14653            };
14654            let lsp_tasks = lsp_tasks.await;
14655
14656            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14657                lsp_tasks
14658                    .into_iter()
14659                    .flat_map(|(kind, tasks)| {
14660                        tasks.into_iter().filter_map(move |(location, task)| {
14661                            Some((kind.clone(), location?, task))
14662                        })
14663                    })
14664                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14665                        let buffer = location.target.buffer;
14666                        let buffer_snapshot = buffer.read(cx).snapshot();
14667                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14668                            |(excerpt_id, snapshot, _)| {
14669                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14670                                    display_snapshot
14671                                        .buffer_snapshot
14672                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14673                                } else {
14674                                    None
14675                                }
14676                            },
14677                        );
14678                        if let Some(offset) = offset {
14679                            let task_buffer_range =
14680                                location.target.range.to_point(&buffer_snapshot);
14681                            let context_buffer_range =
14682                                task_buffer_range.to_offset(&buffer_snapshot);
14683                            let context_range = BufferOffset(context_buffer_range.start)
14684                                ..BufferOffset(context_buffer_range.end);
14685
14686                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14687                                .or_insert_with(|| RunnableTasks {
14688                                    templates: Vec::new(),
14689                                    offset,
14690                                    column: task_buffer_range.start.column,
14691                                    extra_variables: HashMap::default(),
14692                                    context_range,
14693                                })
14694                                .templates
14695                                .push((kind, task.original_task().clone()));
14696                        }
14697
14698                        acc
14699                    })
14700            }) else {
14701                return;
14702            };
14703
14704            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14705                buffer.language_settings(cx).tasks.prefer_lsp
14706            }) else {
14707                return;
14708            };
14709
14710            let rows = Self::runnable_rows(
14711                project,
14712                display_snapshot,
14713                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14714                new_rows,
14715                cx.clone(),
14716            )
14717            .await;
14718            editor
14719                .update(cx, |editor, _| {
14720                    editor.clear_tasks();
14721                    for (key, mut value) in rows {
14722                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14723                            value.templates.extend(lsp_tasks.templates);
14724                        }
14725
14726                        editor.insert_tasks(key, value);
14727                    }
14728                    for (key, value) in lsp_tasks_by_rows {
14729                        editor.insert_tasks(key, value);
14730                    }
14731                })
14732                .ok();
14733        })
14734    }
14735    fn fetch_runnable_ranges(
14736        snapshot: &DisplaySnapshot,
14737        range: Range<Anchor>,
14738    ) -> Vec<language::RunnableRange> {
14739        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14740    }
14741
14742    fn runnable_rows(
14743        project: Entity<Project>,
14744        snapshot: DisplaySnapshot,
14745        prefer_lsp: bool,
14746        runnable_ranges: Vec<RunnableRange>,
14747        cx: AsyncWindowContext,
14748    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14749        cx.spawn(async move |cx| {
14750            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14751            for mut runnable in runnable_ranges {
14752                let Some(tasks) = cx
14753                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14754                    .ok()
14755                else {
14756                    continue;
14757                };
14758                let mut tasks = tasks.await;
14759
14760                if prefer_lsp {
14761                    tasks.retain(|(task_kind, _)| {
14762                        !matches!(task_kind, TaskSourceKind::Language { .. })
14763                    });
14764                }
14765                if tasks.is_empty() {
14766                    continue;
14767                }
14768
14769                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14770                let Some(row) = snapshot
14771                    .buffer_snapshot
14772                    .buffer_line_for_row(MultiBufferRow(point.row))
14773                    .map(|(_, range)| range.start.row)
14774                else {
14775                    continue;
14776                };
14777
14778                let context_range =
14779                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14780                runnable_rows.push((
14781                    (runnable.buffer_id, row),
14782                    RunnableTasks {
14783                        templates: tasks,
14784                        offset: snapshot
14785                            .buffer_snapshot
14786                            .anchor_before(runnable.run_range.start),
14787                        context_range,
14788                        column: point.column,
14789                        extra_variables: runnable.extra_captures,
14790                    },
14791                ));
14792            }
14793            runnable_rows
14794        })
14795    }
14796
14797    fn templates_with_tags(
14798        project: &Entity<Project>,
14799        runnable: &mut Runnable,
14800        cx: &mut App,
14801    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14802        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14803            let (worktree_id, file) = project
14804                .buffer_for_id(runnable.buffer, cx)
14805                .and_then(|buffer| buffer.read(cx).file())
14806                .map(|file| (file.worktree_id(cx), file.clone()))
14807                .unzip();
14808
14809            (
14810                project.task_store().read(cx).task_inventory().cloned(),
14811                worktree_id,
14812                file,
14813            )
14814        });
14815
14816        let tags = mem::take(&mut runnable.tags);
14817        let language = runnable.language.clone();
14818        cx.spawn(async move |cx| {
14819            let mut templates_with_tags = Vec::new();
14820            if let Some(inventory) = inventory {
14821                for RunnableTag(tag) in tags {
14822                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14823                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14824                    }) else {
14825                        return templates_with_tags;
14826                    };
14827                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14828                        move |(_, template)| {
14829                            template.tags.iter().any(|source_tag| source_tag == &tag)
14830                        },
14831                    ));
14832                }
14833            }
14834            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14835
14836            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14837                // Strongest source wins; if we have worktree tag binding, prefer that to
14838                // global and language bindings;
14839                // if we have a global binding, prefer that to language binding.
14840                let first_mismatch = templates_with_tags
14841                    .iter()
14842                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14843                if let Some(index) = first_mismatch {
14844                    templates_with_tags.truncate(index);
14845                }
14846            }
14847
14848            templates_with_tags
14849        })
14850    }
14851
14852    pub fn move_to_enclosing_bracket(
14853        &mut self,
14854        _: &MoveToEnclosingBracket,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) {
14858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14859        self.change_selections(Default::default(), window, cx, |s| {
14860            s.move_offsets_with(|snapshot, selection| {
14861                let Some(enclosing_bracket_ranges) =
14862                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14863                else {
14864                    return;
14865                };
14866
14867                let mut best_length = usize::MAX;
14868                let mut best_inside = false;
14869                let mut best_in_bracket_range = false;
14870                let mut best_destination = None;
14871                for (open, close) in enclosing_bracket_ranges {
14872                    let close = close.to_inclusive();
14873                    let length = close.end() - open.start;
14874                    let inside = selection.start >= open.end && selection.end <= *close.start();
14875                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14876                        || close.contains(&selection.head());
14877
14878                    // If best is next to a bracket and current isn't, skip
14879                    if !in_bracket_range && best_in_bracket_range {
14880                        continue;
14881                    }
14882
14883                    // Prefer smaller lengths unless best is inside and current isn't
14884                    if length > best_length && (best_inside || !inside) {
14885                        continue;
14886                    }
14887
14888                    best_length = length;
14889                    best_inside = inside;
14890                    best_in_bracket_range = in_bracket_range;
14891                    best_destination = Some(
14892                        if close.contains(&selection.start) && close.contains(&selection.end) {
14893                            if inside { open.end } else { open.start }
14894                        } else if inside {
14895                            *close.start()
14896                        } else {
14897                            *close.end()
14898                        },
14899                    );
14900                }
14901
14902                if let Some(destination) = best_destination {
14903                    selection.collapse_to(destination, SelectionGoal::None);
14904                }
14905            })
14906        });
14907    }
14908
14909    pub fn undo_selection(
14910        &mut self,
14911        _: &UndoSelection,
14912        window: &mut Window,
14913        cx: &mut Context<Self>,
14914    ) {
14915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14916        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14917            self.selection_history.mode = SelectionHistoryMode::Undoing;
14918            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14919                this.end_selection(window, cx);
14920                this.change_selections(
14921                    SelectionEffects::scroll(Autoscroll::newest()),
14922                    window,
14923                    cx,
14924                    |s| s.select_anchors(entry.selections.to_vec()),
14925                );
14926            });
14927            self.selection_history.mode = SelectionHistoryMode::Normal;
14928
14929            self.select_next_state = entry.select_next_state;
14930            self.select_prev_state = entry.select_prev_state;
14931            self.add_selections_state = entry.add_selections_state;
14932        }
14933    }
14934
14935    pub fn redo_selection(
14936        &mut self,
14937        _: &RedoSelection,
14938        window: &mut Window,
14939        cx: &mut Context<Self>,
14940    ) {
14941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14942        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14943            self.selection_history.mode = SelectionHistoryMode::Redoing;
14944            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14945                this.end_selection(window, cx);
14946                this.change_selections(
14947                    SelectionEffects::scroll(Autoscroll::newest()),
14948                    window,
14949                    cx,
14950                    |s| s.select_anchors(entry.selections.to_vec()),
14951                );
14952            });
14953            self.selection_history.mode = SelectionHistoryMode::Normal;
14954
14955            self.select_next_state = entry.select_next_state;
14956            self.select_prev_state = entry.select_prev_state;
14957            self.add_selections_state = entry.add_selections_state;
14958        }
14959    }
14960
14961    pub fn expand_excerpts(
14962        &mut self,
14963        action: &ExpandExcerpts,
14964        _: &mut Window,
14965        cx: &mut Context<Self>,
14966    ) {
14967        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14968    }
14969
14970    pub fn expand_excerpts_down(
14971        &mut self,
14972        action: &ExpandExcerptsDown,
14973        _: &mut Window,
14974        cx: &mut Context<Self>,
14975    ) {
14976        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14977    }
14978
14979    pub fn expand_excerpts_up(
14980        &mut self,
14981        action: &ExpandExcerptsUp,
14982        _: &mut Window,
14983        cx: &mut Context<Self>,
14984    ) {
14985        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14986    }
14987
14988    pub fn expand_excerpts_for_direction(
14989        &mut self,
14990        lines: u32,
14991        direction: ExpandExcerptDirection,
14992
14993        cx: &mut Context<Self>,
14994    ) {
14995        let selections = self.selections.disjoint_anchors();
14996
14997        let lines = if lines == 0 {
14998            EditorSettings::get_global(cx).expand_excerpt_lines
14999        } else {
15000            lines
15001        };
15002
15003        self.buffer.update(cx, |buffer, cx| {
15004            let snapshot = buffer.snapshot(cx);
15005            let mut excerpt_ids = selections
15006                .iter()
15007                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15008                .collect::<Vec<_>>();
15009            excerpt_ids.sort();
15010            excerpt_ids.dedup();
15011            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15012        })
15013    }
15014
15015    pub fn expand_excerpt(
15016        &mut self,
15017        excerpt: ExcerptId,
15018        direction: ExpandExcerptDirection,
15019        window: &mut Window,
15020        cx: &mut Context<Self>,
15021    ) {
15022        let current_scroll_position = self.scroll_position(cx);
15023        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15024        let mut should_scroll_up = false;
15025
15026        if direction == ExpandExcerptDirection::Down {
15027            let multi_buffer = self.buffer.read(cx);
15028            let snapshot = multi_buffer.snapshot(cx);
15029            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15030                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15031                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15032                        let buffer_snapshot = buffer.read(cx).snapshot();
15033                        let excerpt_end_row =
15034                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15035                        let last_row = buffer_snapshot.max_point().row;
15036                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15037                        should_scroll_up = lines_below >= lines_to_expand;
15038                    }
15039                }
15040            }
15041        }
15042
15043        self.buffer.update(cx, |buffer, cx| {
15044            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15045        });
15046
15047        if should_scroll_up {
15048            let new_scroll_position =
15049                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15050            self.set_scroll_position(new_scroll_position, window, cx);
15051        }
15052    }
15053
15054    pub fn go_to_singleton_buffer_point(
15055        &mut self,
15056        point: Point,
15057        window: &mut Window,
15058        cx: &mut Context<Self>,
15059    ) {
15060        self.go_to_singleton_buffer_range(point..point, window, cx);
15061    }
15062
15063    pub fn go_to_singleton_buffer_range(
15064        &mut self,
15065        range: Range<Point>,
15066        window: &mut Window,
15067        cx: &mut Context<Self>,
15068    ) {
15069        let multibuffer = self.buffer().read(cx);
15070        let Some(buffer) = multibuffer.as_singleton() else {
15071            return;
15072        };
15073        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15074            return;
15075        };
15076        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15077            return;
15078        };
15079        self.change_selections(
15080            SelectionEffects::default().nav_history(true),
15081            window,
15082            cx,
15083            |s| s.select_anchor_ranges([start..end]),
15084        );
15085    }
15086
15087    pub fn go_to_diagnostic(
15088        &mut self,
15089        action: &GoToDiagnostic,
15090        window: &mut Window,
15091        cx: &mut Context<Self>,
15092    ) {
15093        if !self.diagnostics_enabled() {
15094            return;
15095        }
15096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15097        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15098    }
15099
15100    pub fn go_to_prev_diagnostic(
15101        &mut self,
15102        action: &GoToPreviousDiagnostic,
15103        window: &mut Window,
15104        cx: &mut Context<Self>,
15105    ) {
15106        if !self.diagnostics_enabled() {
15107            return;
15108        }
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15111    }
15112
15113    pub fn go_to_diagnostic_impl(
15114        &mut self,
15115        direction: Direction,
15116        severity: GoToDiagnosticSeverityFilter,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) {
15120        let buffer = self.buffer.read(cx).snapshot(cx);
15121        let selection = self.selections.newest::<usize>(cx);
15122
15123        let mut active_group_id = None;
15124        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15125            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15126                active_group_id = Some(active_group.group_id);
15127            }
15128        }
15129
15130        fn filtered(
15131            snapshot: EditorSnapshot,
15132            severity: GoToDiagnosticSeverityFilter,
15133            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15134        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15135            diagnostics
15136                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15137                .filter(|entry| entry.range.start != entry.range.end)
15138                .filter(|entry| !entry.diagnostic.is_unnecessary)
15139                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15140        }
15141
15142        let snapshot = self.snapshot(window, cx);
15143        let before = filtered(
15144            snapshot.clone(),
15145            severity,
15146            buffer
15147                .diagnostics_in_range(0..selection.start)
15148                .filter(|entry| entry.range.start <= selection.start),
15149        );
15150        let after = filtered(
15151            snapshot,
15152            severity,
15153            buffer
15154                .diagnostics_in_range(selection.start..buffer.len())
15155                .filter(|entry| entry.range.start >= selection.start),
15156        );
15157
15158        let mut found: Option<DiagnosticEntry<usize>> = None;
15159        if direction == Direction::Prev {
15160            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15161            {
15162                for diagnostic in prev_diagnostics.into_iter().rev() {
15163                    if diagnostic.range.start != selection.start
15164                        || active_group_id
15165                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15166                    {
15167                        found = Some(diagnostic);
15168                        break 'outer;
15169                    }
15170                }
15171            }
15172        } else {
15173            for diagnostic in after.chain(before) {
15174                if diagnostic.range.start != selection.start
15175                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15176                {
15177                    found = Some(diagnostic);
15178                    break;
15179                }
15180            }
15181        }
15182        let Some(next_diagnostic) = found else {
15183            return;
15184        };
15185
15186        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15187            return;
15188        };
15189        self.change_selections(Default::default(), window, cx, |s| {
15190            s.select_ranges(vec![
15191                next_diagnostic.range.start..next_diagnostic.range.start,
15192            ])
15193        });
15194        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15195        self.refresh_inline_completion(false, true, window, cx);
15196    }
15197
15198    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200        let snapshot = self.snapshot(window, cx);
15201        let selection = self.selections.newest::<Point>(cx);
15202        self.go_to_hunk_before_or_after_position(
15203            &snapshot,
15204            selection.head(),
15205            Direction::Next,
15206            window,
15207            cx,
15208        );
15209    }
15210
15211    pub fn go_to_hunk_before_or_after_position(
15212        &mut self,
15213        snapshot: &EditorSnapshot,
15214        position: Point,
15215        direction: Direction,
15216        window: &mut Window,
15217        cx: &mut Context<Editor>,
15218    ) {
15219        let row = if direction == Direction::Next {
15220            self.hunk_after_position(snapshot, position)
15221                .map(|hunk| hunk.row_range.start)
15222        } else {
15223            self.hunk_before_position(snapshot, position)
15224        };
15225
15226        if let Some(row) = row {
15227            let destination = Point::new(row.0, 0);
15228            let autoscroll = Autoscroll::center();
15229
15230            self.unfold_ranges(&[destination..destination], false, false, cx);
15231            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15232                s.select_ranges([destination..destination]);
15233            });
15234        }
15235    }
15236
15237    fn hunk_after_position(
15238        &mut self,
15239        snapshot: &EditorSnapshot,
15240        position: Point,
15241    ) -> Option<MultiBufferDiffHunk> {
15242        snapshot
15243            .buffer_snapshot
15244            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15245            .find(|hunk| hunk.row_range.start.0 > position.row)
15246            .or_else(|| {
15247                snapshot
15248                    .buffer_snapshot
15249                    .diff_hunks_in_range(Point::zero()..position)
15250                    .find(|hunk| hunk.row_range.end.0 < position.row)
15251            })
15252    }
15253
15254    fn go_to_prev_hunk(
15255        &mut self,
15256        _: &GoToPreviousHunk,
15257        window: &mut Window,
15258        cx: &mut Context<Self>,
15259    ) {
15260        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15261        let snapshot = self.snapshot(window, cx);
15262        let selection = self.selections.newest::<Point>(cx);
15263        self.go_to_hunk_before_or_after_position(
15264            &snapshot,
15265            selection.head(),
15266            Direction::Prev,
15267            window,
15268            cx,
15269        );
15270    }
15271
15272    fn hunk_before_position(
15273        &mut self,
15274        snapshot: &EditorSnapshot,
15275        position: Point,
15276    ) -> Option<MultiBufferRow> {
15277        snapshot
15278            .buffer_snapshot
15279            .diff_hunk_before(position)
15280            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15281    }
15282
15283    fn go_to_next_change(
15284        &mut self,
15285        _: &GoToNextChange,
15286        window: &mut Window,
15287        cx: &mut Context<Self>,
15288    ) {
15289        if let Some(selections) = self
15290            .change_list
15291            .next_change(1, Direction::Next)
15292            .map(|s| s.to_vec())
15293        {
15294            self.change_selections(Default::default(), window, cx, |s| {
15295                let map = s.display_map();
15296                s.select_display_ranges(selections.iter().map(|a| {
15297                    let point = a.to_display_point(&map);
15298                    point..point
15299                }))
15300            })
15301        }
15302    }
15303
15304    fn go_to_previous_change(
15305        &mut self,
15306        _: &GoToPreviousChange,
15307        window: &mut Window,
15308        cx: &mut Context<Self>,
15309    ) {
15310        if let Some(selections) = self
15311            .change_list
15312            .next_change(1, Direction::Prev)
15313            .map(|s| s.to_vec())
15314        {
15315            self.change_selections(Default::default(), window, cx, |s| {
15316                let map = s.display_map();
15317                s.select_display_ranges(selections.iter().map(|a| {
15318                    let point = a.to_display_point(&map);
15319                    point..point
15320                }))
15321            })
15322        }
15323    }
15324
15325    fn go_to_line<T: 'static>(
15326        &mut self,
15327        position: Anchor,
15328        highlight_color: Option<Hsla>,
15329        window: &mut Window,
15330        cx: &mut Context<Self>,
15331    ) {
15332        let snapshot = self.snapshot(window, cx).display_snapshot;
15333        let position = position.to_point(&snapshot.buffer_snapshot);
15334        let start = snapshot
15335            .buffer_snapshot
15336            .clip_point(Point::new(position.row, 0), Bias::Left);
15337        let end = start + Point::new(1, 0);
15338        let start = snapshot.buffer_snapshot.anchor_before(start);
15339        let end = snapshot.buffer_snapshot.anchor_before(end);
15340
15341        self.highlight_rows::<T>(
15342            start..end,
15343            highlight_color
15344                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15345            Default::default(),
15346            cx,
15347        );
15348
15349        if self.buffer.read(cx).is_singleton() {
15350            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15351        }
15352    }
15353
15354    pub fn go_to_definition(
15355        &mut self,
15356        _: &GoToDefinition,
15357        window: &mut Window,
15358        cx: &mut Context<Self>,
15359    ) -> Task<Result<Navigated>> {
15360        let definition =
15361            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15362        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15363        cx.spawn_in(window, async move |editor, cx| {
15364            if definition.await? == Navigated::Yes {
15365                return Ok(Navigated::Yes);
15366            }
15367            match fallback_strategy {
15368                GoToDefinitionFallback::None => Ok(Navigated::No),
15369                GoToDefinitionFallback::FindAllReferences => {
15370                    match editor.update_in(cx, |editor, window, cx| {
15371                        editor.find_all_references(&FindAllReferences, window, cx)
15372                    })? {
15373                        Some(references) => references.await,
15374                        None => Ok(Navigated::No),
15375                    }
15376                }
15377            }
15378        })
15379    }
15380
15381    pub fn go_to_declaration(
15382        &mut self,
15383        _: &GoToDeclaration,
15384        window: &mut Window,
15385        cx: &mut Context<Self>,
15386    ) -> Task<Result<Navigated>> {
15387        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15388    }
15389
15390    pub fn go_to_declaration_split(
15391        &mut self,
15392        _: &GoToDeclaration,
15393        window: &mut Window,
15394        cx: &mut Context<Self>,
15395    ) -> Task<Result<Navigated>> {
15396        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15397    }
15398
15399    pub fn go_to_implementation(
15400        &mut self,
15401        _: &GoToImplementation,
15402        window: &mut Window,
15403        cx: &mut Context<Self>,
15404    ) -> Task<Result<Navigated>> {
15405        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15406    }
15407
15408    pub fn go_to_implementation_split(
15409        &mut self,
15410        _: &GoToImplementationSplit,
15411        window: &mut Window,
15412        cx: &mut Context<Self>,
15413    ) -> Task<Result<Navigated>> {
15414        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15415    }
15416
15417    pub fn go_to_type_definition(
15418        &mut self,
15419        _: &GoToTypeDefinition,
15420        window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) -> Task<Result<Navigated>> {
15423        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15424    }
15425
15426    pub fn go_to_definition_split(
15427        &mut self,
15428        _: &GoToDefinitionSplit,
15429        window: &mut Window,
15430        cx: &mut Context<Self>,
15431    ) -> Task<Result<Navigated>> {
15432        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15433    }
15434
15435    pub fn go_to_type_definition_split(
15436        &mut self,
15437        _: &GoToTypeDefinitionSplit,
15438        window: &mut Window,
15439        cx: &mut Context<Self>,
15440    ) -> Task<Result<Navigated>> {
15441        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15442    }
15443
15444    fn go_to_definition_of_kind(
15445        &mut self,
15446        kind: GotoDefinitionKind,
15447        split: bool,
15448        window: &mut Window,
15449        cx: &mut Context<Self>,
15450    ) -> Task<Result<Navigated>> {
15451        let Some(provider) = self.semantics_provider.clone() else {
15452            return Task::ready(Ok(Navigated::No));
15453        };
15454        let head = self.selections.newest::<usize>(cx).head();
15455        let buffer = self.buffer.read(cx);
15456        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15457            text_anchor
15458        } else {
15459            return Task::ready(Ok(Navigated::No));
15460        };
15461
15462        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15463            return Task::ready(Ok(Navigated::No));
15464        };
15465
15466        cx.spawn_in(window, async move |editor, cx| {
15467            let definitions = definitions.await?;
15468            let navigated = editor
15469                .update_in(cx, |editor, window, cx| {
15470                    editor.navigate_to_hover_links(
15471                        Some(kind),
15472                        definitions
15473                            .into_iter()
15474                            .filter(|location| {
15475                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15476                            })
15477                            .map(HoverLink::Text)
15478                            .collect::<Vec<_>>(),
15479                        split,
15480                        window,
15481                        cx,
15482                    )
15483                })?
15484                .await?;
15485            anyhow::Ok(navigated)
15486        })
15487    }
15488
15489    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15490        let selection = self.selections.newest_anchor();
15491        let head = selection.head();
15492        let tail = selection.tail();
15493
15494        let Some((buffer, start_position)) =
15495            self.buffer.read(cx).text_anchor_for_position(head, cx)
15496        else {
15497            return;
15498        };
15499
15500        let end_position = if head != tail {
15501            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15502                return;
15503            };
15504            Some(pos)
15505        } else {
15506            None
15507        };
15508
15509        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15510            let url = if let Some(end_pos) = end_position {
15511                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15512            } else {
15513                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15514            };
15515
15516            if let Some(url) = url {
15517                editor.update(cx, |_, cx| {
15518                    cx.open_url(&url);
15519                })
15520            } else {
15521                Ok(())
15522            }
15523        });
15524
15525        url_finder.detach();
15526    }
15527
15528    pub fn open_selected_filename(
15529        &mut self,
15530        _: &OpenSelectedFilename,
15531        window: &mut Window,
15532        cx: &mut Context<Self>,
15533    ) {
15534        let Some(workspace) = self.workspace() else {
15535            return;
15536        };
15537
15538        let position = self.selections.newest_anchor().head();
15539
15540        let Some((buffer, buffer_position)) =
15541            self.buffer.read(cx).text_anchor_for_position(position, cx)
15542        else {
15543            return;
15544        };
15545
15546        let project = self.project.clone();
15547
15548        cx.spawn_in(window, async move |_, cx| {
15549            let result = find_file(&buffer, project, buffer_position, cx).await;
15550
15551            if let Some((_, path)) = result {
15552                workspace
15553                    .update_in(cx, |workspace, window, cx| {
15554                        workspace.open_resolved_path(path, window, cx)
15555                    })?
15556                    .await?;
15557            }
15558            anyhow::Ok(())
15559        })
15560        .detach();
15561    }
15562
15563    pub(crate) fn navigate_to_hover_links(
15564        &mut self,
15565        kind: Option<GotoDefinitionKind>,
15566        mut definitions: Vec<HoverLink>,
15567        split: bool,
15568        window: &mut Window,
15569        cx: &mut Context<Editor>,
15570    ) -> Task<Result<Navigated>> {
15571        // If there is one definition, just open it directly
15572        if definitions.len() == 1 {
15573            let definition = definitions.pop().unwrap();
15574
15575            enum TargetTaskResult {
15576                Location(Option<Location>),
15577                AlreadyNavigated,
15578            }
15579
15580            let target_task = match definition {
15581                HoverLink::Text(link) => {
15582                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15583                }
15584                HoverLink::InlayHint(lsp_location, server_id) => {
15585                    let computation =
15586                        self.compute_target_location(lsp_location, server_id, window, cx);
15587                    cx.background_spawn(async move {
15588                        let location = computation.await?;
15589                        Ok(TargetTaskResult::Location(location))
15590                    })
15591                }
15592                HoverLink::Url(url) => {
15593                    cx.open_url(&url);
15594                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15595                }
15596                HoverLink::File(path) => {
15597                    if let Some(workspace) = self.workspace() {
15598                        cx.spawn_in(window, async move |_, cx| {
15599                            workspace
15600                                .update_in(cx, |workspace, window, cx| {
15601                                    workspace.open_resolved_path(path, window, cx)
15602                                })?
15603                                .await
15604                                .map(|_| TargetTaskResult::AlreadyNavigated)
15605                        })
15606                    } else {
15607                        Task::ready(Ok(TargetTaskResult::Location(None)))
15608                    }
15609                }
15610            };
15611            cx.spawn_in(window, async move |editor, cx| {
15612                let target = match target_task.await.context("target resolution task")? {
15613                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15614                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15615                    TargetTaskResult::Location(Some(target)) => target,
15616                };
15617
15618                editor.update_in(cx, |editor, window, cx| {
15619                    let Some(workspace) = editor.workspace() else {
15620                        return Navigated::No;
15621                    };
15622                    let pane = workspace.read(cx).active_pane().clone();
15623
15624                    let range = target.range.to_point(target.buffer.read(cx));
15625                    let range = editor.range_for_match(&range);
15626                    let range = collapse_multiline_range(range);
15627
15628                    if !split
15629                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15630                    {
15631                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15632                    } else {
15633                        window.defer(cx, move |window, cx| {
15634                            let target_editor: Entity<Self> =
15635                                workspace.update(cx, |workspace, cx| {
15636                                    let pane = if split {
15637                                        workspace.adjacent_pane(window, cx)
15638                                    } else {
15639                                        workspace.active_pane().clone()
15640                                    };
15641
15642                                    workspace.open_project_item(
15643                                        pane,
15644                                        target.buffer.clone(),
15645                                        true,
15646                                        true,
15647                                        window,
15648                                        cx,
15649                                    )
15650                                });
15651                            target_editor.update(cx, |target_editor, cx| {
15652                                // When selecting a definition in a different buffer, disable the nav history
15653                                // to avoid creating a history entry at the previous cursor location.
15654                                pane.update(cx, |pane, _| pane.disable_history());
15655                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15656                                pane.update(cx, |pane, _| pane.enable_history());
15657                            });
15658                        });
15659                    }
15660                    Navigated::Yes
15661                })
15662            })
15663        } else if !definitions.is_empty() {
15664            cx.spawn_in(window, async move |editor, cx| {
15665                let (title, location_tasks, workspace) = editor
15666                    .update_in(cx, |editor, window, cx| {
15667                        let tab_kind = match kind {
15668                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15669                            _ => "Definitions",
15670                        };
15671                        let title = definitions
15672                            .iter()
15673                            .find_map(|definition| match definition {
15674                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15675                                    let buffer = origin.buffer.read(cx);
15676                                    format!(
15677                                        "{} for {}",
15678                                        tab_kind,
15679                                        buffer
15680                                            .text_for_range(origin.range.clone())
15681                                            .collect::<String>()
15682                                    )
15683                                }),
15684                                HoverLink::InlayHint(_, _) => None,
15685                                HoverLink::Url(_) => None,
15686                                HoverLink::File(_) => None,
15687                            })
15688                            .unwrap_or(tab_kind.to_string());
15689                        let location_tasks = definitions
15690                            .into_iter()
15691                            .map(|definition| match definition {
15692                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15693                                HoverLink::InlayHint(lsp_location, server_id) => editor
15694                                    .compute_target_location(lsp_location, server_id, window, cx),
15695                                HoverLink::Url(_) => Task::ready(Ok(None)),
15696                                HoverLink::File(_) => Task::ready(Ok(None)),
15697                            })
15698                            .collect::<Vec<_>>();
15699                        (title, location_tasks, editor.workspace().clone())
15700                    })
15701                    .context("location tasks preparation")?;
15702
15703                let locations: Vec<Location> = future::join_all(location_tasks)
15704                    .await
15705                    .into_iter()
15706                    .filter_map(|location| location.transpose())
15707                    .collect::<Result<_>>()
15708                    .context("location tasks")?;
15709
15710                if locations.is_empty() {
15711                    return Ok(Navigated::No);
15712                }
15713
15714                let Some(workspace) = workspace else {
15715                    return Ok(Navigated::No);
15716                };
15717
15718                let opened = workspace
15719                    .update_in(cx, |workspace, window, cx| {
15720                        Self::open_locations_in_multibuffer(
15721                            workspace,
15722                            locations,
15723                            title,
15724                            split,
15725                            MultibufferSelectionMode::First,
15726                            window,
15727                            cx,
15728                        )
15729                    })
15730                    .ok();
15731
15732                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15733            })
15734        } else {
15735            Task::ready(Ok(Navigated::No))
15736        }
15737    }
15738
15739    fn compute_target_location(
15740        &self,
15741        lsp_location: lsp::Location,
15742        server_id: LanguageServerId,
15743        window: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) -> Task<anyhow::Result<Option<Location>>> {
15746        let Some(project) = self.project.clone() else {
15747            return Task::ready(Ok(None));
15748        };
15749
15750        cx.spawn_in(window, async move |editor, cx| {
15751            let location_task = editor.update(cx, |_, cx| {
15752                project.update(cx, |project, cx| {
15753                    let language_server_name = project
15754                        .language_server_statuses(cx)
15755                        .find(|(id, _)| server_id == *id)
15756                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15757                    language_server_name.map(|language_server_name| {
15758                        project.open_local_buffer_via_lsp(
15759                            lsp_location.uri.clone(),
15760                            server_id,
15761                            language_server_name,
15762                            cx,
15763                        )
15764                    })
15765                })
15766            })?;
15767            let location = match location_task {
15768                Some(task) => Some({
15769                    let target_buffer_handle = task.await.context("open local buffer")?;
15770                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15771                        let target_start = target_buffer
15772                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15773                        let target_end = target_buffer
15774                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15775                        target_buffer.anchor_after(target_start)
15776                            ..target_buffer.anchor_before(target_end)
15777                    })?;
15778                    Location {
15779                        buffer: target_buffer_handle,
15780                        range,
15781                    }
15782                }),
15783                None => None,
15784            };
15785            Ok(location)
15786        })
15787    }
15788
15789    pub fn find_all_references(
15790        &mut self,
15791        _: &FindAllReferences,
15792        window: &mut Window,
15793        cx: &mut Context<Self>,
15794    ) -> Option<Task<Result<Navigated>>> {
15795        let selection = self.selections.newest::<usize>(cx);
15796        let multi_buffer = self.buffer.read(cx);
15797        let head = selection.head();
15798
15799        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15800        let head_anchor = multi_buffer_snapshot.anchor_at(
15801            head,
15802            if head < selection.tail() {
15803                Bias::Right
15804            } else {
15805                Bias::Left
15806            },
15807        );
15808
15809        match self
15810            .find_all_references_task_sources
15811            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15812        {
15813            Ok(_) => {
15814                log::info!(
15815                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15816                );
15817                return None;
15818            }
15819            Err(i) => {
15820                self.find_all_references_task_sources.insert(i, head_anchor);
15821            }
15822        }
15823
15824        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15825        let workspace = self.workspace()?;
15826        let project = workspace.read(cx).project().clone();
15827        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15828        Some(cx.spawn_in(window, async move |editor, cx| {
15829            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15830                if let Ok(i) = editor
15831                    .find_all_references_task_sources
15832                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15833                {
15834                    editor.find_all_references_task_sources.remove(i);
15835                }
15836            });
15837
15838            let locations = references.await?;
15839            if locations.is_empty() {
15840                return anyhow::Ok(Navigated::No);
15841            }
15842
15843            workspace.update_in(cx, |workspace, window, cx| {
15844                let title = locations
15845                    .first()
15846                    .as_ref()
15847                    .map(|location| {
15848                        let buffer = location.buffer.read(cx);
15849                        format!(
15850                            "References to `{}`",
15851                            buffer
15852                                .text_for_range(location.range.clone())
15853                                .collect::<String>()
15854                        )
15855                    })
15856                    .unwrap();
15857                Self::open_locations_in_multibuffer(
15858                    workspace,
15859                    locations,
15860                    title,
15861                    false,
15862                    MultibufferSelectionMode::First,
15863                    window,
15864                    cx,
15865                );
15866                Navigated::Yes
15867            })
15868        }))
15869    }
15870
15871    /// Opens a multibuffer with the given project locations in it
15872    pub fn open_locations_in_multibuffer(
15873        workspace: &mut Workspace,
15874        mut locations: Vec<Location>,
15875        title: String,
15876        split: bool,
15877        multibuffer_selection_mode: MultibufferSelectionMode,
15878        window: &mut Window,
15879        cx: &mut Context<Workspace>,
15880    ) {
15881        if locations.is_empty() {
15882            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15883            return;
15884        }
15885
15886        // If there are multiple definitions, open them in a multibuffer
15887        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15888        let mut locations = locations.into_iter().peekable();
15889        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15890        let capability = workspace.project().read(cx).capability();
15891
15892        let excerpt_buffer = cx.new(|cx| {
15893            let mut multibuffer = MultiBuffer::new(capability);
15894            while let Some(location) = locations.next() {
15895                let buffer = location.buffer.read(cx);
15896                let mut ranges_for_buffer = Vec::new();
15897                let range = location.range.to_point(buffer);
15898                ranges_for_buffer.push(range.clone());
15899
15900                while let Some(next_location) = locations.peek() {
15901                    if next_location.buffer == location.buffer {
15902                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15903                        locations.next();
15904                    } else {
15905                        break;
15906                    }
15907                }
15908
15909                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15910                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15911                    PathKey::for_buffer(&location.buffer, cx),
15912                    location.buffer.clone(),
15913                    ranges_for_buffer,
15914                    DEFAULT_MULTIBUFFER_CONTEXT,
15915                    cx,
15916                );
15917                ranges.extend(new_ranges)
15918            }
15919
15920            multibuffer.with_title(title)
15921        });
15922
15923        let editor = cx.new(|cx| {
15924            Editor::for_multibuffer(
15925                excerpt_buffer,
15926                Some(workspace.project().clone()),
15927                window,
15928                cx,
15929            )
15930        });
15931        editor.update(cx, |editor, cx| {
15932            match multibuffer_selection_mode {
15933                MultibufferSelectionMode::First => {
15934                    if let Some(first_range) = ranges.first() {
15935                        editor.change_selections(
15936                            SelectionEffects::no_scroll(),
15937                            window,
15938                            cx,
15939                            |selections| {
15940                                selections.clear_disjoint();
15941                                selections
15942                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15943                            },
15944                        );
15945                    }
15946                    editor.highlight_background::<Self>(
15947                        &ranges,
15948                        |theme| theme.colors().editor_highlighted_line_background,
15949                        cx,
15950                    );
15951                }
15952                MultibufferSelectionMode::All => {
15953                    editor.change_selections(
15954                        SelectionEffects::no_scroll(),
15955                        window,
15956                        cx,
15957                        |selections| {
15958                            selections.clear_disjoint();
15959                            selections.select_anchor_ranges(ranges);
15960                        },
15961                    );
15962                }
15963            }
15964            editor.register_buffers_with_language_servers(cx);
15965        });
15966
15967        let item = Box::new(editor);
15968        let item_id = item.item_id();
15969
15970        if split {
15971            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15972        } else {
15973            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15974                let (preview_item_id, preview_item_idx) =
15975                    workspace.active_pane().read_with(cx, |pane, _| {
15976                        (pane.preview_item_id(), pane.preview_item_idx())
15977                    });
15978
15979                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15980
15981                if let Some(preview_item_id) = preview_item_id {
15982                    workspace.active_pane().update(cx, |pane, cx| {
15983                        pane.remove_item(preview_item_id, false, false, window, cx);
15984                    });
15985                }
15986            } else {
15987                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15988            }
15989        }
15990        workspace.active_pane().update(cx, |pane, cx| {
15991            pane.set_preview_item_id(Some(item_id), cx);
15992        });
15993    }
15994
15995    pub fn rename(
15996        &mut self,
15997        _: &Rename,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) -> Option<Task<Result<()>>> {
16001        use language::ToOffset as _;
16002
16003        let provider = self.semantics_provider.clone()?;
16004        let selection = self.selections.newest_anchor().clone();
16005        let (cursor_buffer, cursor_buffer_position) = self
16006            .buffer
16007            .read(cx)
16008            .text_anchor_for_position(selection.head(), cx)?;
16009        let (tail_buffer, cursor_buffer_position_end) = self
16010            .buffer
16011            .read(cx)
16012            .text_anchor_for_position(selection.tail(), cx)?;
16013        if tail_buffer != cursor_buffer {
16014            return None;
16015        }
16016
16017        let snapshot = cursor_buffer.read(cx).snapshot();
16018        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16019        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16020        let prepare_rename = provider
16021            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16022            .unwrap_or_else(|| Task::ready(Ok(None)));
16023        drop(snapshot);
16024
16025        Some(cx.spawn_in(window, async move |this, cx| {
16026            let rename_range = if let Some(range) = prepare_rename.await? {
16027                Some(range)
16028            } else {
16029                this.update(cx, |this, cx| {
16030                    let buffer = this.buffer.read(cx).snapshot(cx);
16031                    let mut buffer_highlights = this
16032                        .document_highlights_for_position(selection.head(), &buffer)
16033                        .filter(|highlight| {
16034                            highlight.start.excerpt_id == selection.head().excerpt_id
16035                                && highlight.end.excerpt_id == selection.head().excerpt_id
16036                        });
16037                    buffer_highlights
16038                        .next()
16039                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16040                })?
16041            };
16042            if let Some(rename_range) = rename_range {
16043                this.update_in(cx, |this, window, cx| {
16044                    let snapshot = cursor_buffer.read(cx).snapshot();
16045                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16046                    let cursor_offset_in_rename_range =
16047                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16048                    let cursor_offset_in_rename_range_end =
16049                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16050
16051                    this.take_rename(false, window, cx);
16052                    let buffer = this.buffer.read(cx).read(cx);
16053                    let cursor_offset = selection.head().to_offset(&buffer);
16054                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16055                    let rename_end = rename_start + rename_buffer_range.len();
16056                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16057                    let mut old_highlight_id = None;
16058                    let old_name: Arc<str> = buffer
16059                        .chunks(rename_start..rename_end, true)
16060                        .map(|chunk| {
16061                            if old_highlight_id.is_none() {
16062                                old_highlight_id = chunk.syntax_highlight_id;
16063                            }
16064                            chunk.text
16065                        })
16066                        .collect::<String>()
16067                        .into();
16068
16069                    drop(buffer);
16070
16071                    // Position the selection in the rename editor so that it matches the current selection.
16072                    this.show_local_selections = false;
16073                    let rename_editor = cx.new(|cx| {
16074                        let mut editor = Editor::single_line(window, cx);
16075                        editor.buffer.update(cx, |buffer, cx| {
16076                            buffer.edit([(0..0, old_name.clone())], None, cx)
16077                        });
16078                        let rename_selection_range = match cursor_offset_in_rename_range
16079                            .cmp(&cursor_offset_in_rename_range_end)
16080                        {
16081                            Ordering::Equal => {
16082                                editor.select_all(&SelectAll, window, cx);
16083                                return editor;
16084                            }
16085                            Ordering::Less => {
16086                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16087                            }
16088                            Ordering::Greater => {
16089                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16090                            }
16091                        };
16092                        if rename_selection_range.end > old_name.len() {
16093                            editor.select_all(&SelectAll, window, cx);
16094                        } else {
16095                            editor.change_selections(Default::default(), window, cx, |s| {
16096                                s.select_ranges([rename_selection_range]);
16097                            });
16098                        }
16099                        editor
16100                    });
16101                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16102                        if e == &EditorEvent::Focused {
16103                            cx.emit(EditorEvent::FocusedIn)
16104                        }
16105                    })
16106                    .detach();
16107
16108                    let write_highlights =
16109                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16110                    let read_highlights =
16111                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16112                    let ranges = write_highlights
16113                        .iter()
16114                        .flat_map(|(_, ranges)| ranges.iter())
16115                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16116                        .cloned()
16117                        .collect();
16118
16119                    this.highlight_text::<Rename>(
16120                        ranges,
16121                        HighlightStyle {
16122                            fade_out: Some(0.6),
16123                            ..Default::default()
16124                        },
16125                        cx,
16126                    );
16127                    let rename_focus_handle = rename_editor.focus_handle(cx);
16128                    window.focus(&rename_focus_handle);
16129                    let block_id = this.insert_blocks(
16130                        [BlockProperties {
16131                            style: BlockStyle::Flex,
16132                            placement: BlockPlacement::Below(range.start),
16133                            height: Some(1),
16134                            render: Arc::new({
16135                                let rename_editor = rename_editor.clone();
16136                                move |cx: &mut BlockContext| {
16137                                    let mut text_style = cx.editor_style.text.clone();
16138                                    if let Some(highlight_style) = old_highlight_id
16139                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16140                                    {
16141                                        text_style = text_style.highlight(highlight_style);
16142                                    }
16143                                    div()
16144                                        .block_mouse_except_scroll()
16145                                        .pl(cx.anchor_x)
16146                                        .child(EditorElement::new(
16147                                            &rename_editor,
16148                                            EditorStyle {
16149                                                background: cx.theme().system().transparent,
16150                                                local_player: cx.editor_style.local_player,
16151                                                text: text_style,
16152                                                scrollbar_width: cx.editor_style.scrollbar_width,
16153                                                syntax: cx.editor_style.syntax.clone(),
16154                                                status: cx.editor_style.status.clone(),
16155                                                inlay_hints_style: HighlightStyle {
16156                                                    font_weight: Some(FontWeight::BOLD),
16157                                                    ..make_inlay_hints_style(cx.app)
16158                                                },
16159                                                inline_completion_styles: make_suggestion_styles(
16160                                                    cx.app,
16161                                                ),
16162                                                ..EditorStyle::default()
16163                                            },
16164                                        ))
16165                                        .into_any_element()
16166                                }
16167                            }),
16168                            priority: 0,
16169                        }],
16170                        Some(Autoscroll::fit()),
16171                        cx,
16172                    )[0];
16173                    this.pending_rename = Some(RenameState {
16174                        range,
16175                        old_name,
16176                        editor: rename_editor,
16177                        block_id,
16178                    });
16179                })?;
16180            }
16181
16182            Ok(())
16183        }))
16184    }
16185
16186    pub fn confirm_rename(
16187        &mut self,
16188        _: &ConfirmRename,
16189        window: &mut Window,
16190        cx: &mut Context<Self>,
16191    ) -> Option<Task<Result<()>>> {
16192        let rename = self.take_rename(false, window, cx)?;
16193        let workspace = self.workspace()?.downgrade();
16194        let (buffer, start) = self
16195            .buffer
16196            .read(cx)
16197            .text_anchor_for_position(rename.range.start, cx)?;
16198        let (end_buffer, _) = self
16199            .buffer
16200            .read(cx)
16201            .text_anchor_for_position(rename.range.end, cx)?;
16202        if buffer != end_buffer {
16203            return None;
16204        }
16205
16206        let old_name = rename.old_name;
16207        let new_name = rename.editor.read(cx).text(cx);
16208
16209        let rename = self.semantics_provider.as_ref()?.perform_rename(
16210            &buffer,
16211            start,
16212            new_name.clone(),
16213            cx,
16214        )?;
16215
16216        Some(cx.spawn_in(window, async move |editor, cx| {
16217            let project_transaction = rename.await?;
16218            Self::open_project_transaction(
16219                &editor,
16220                workspace,
16221                project_transaction,
16222                format!("Rename: {}{}", old_name, new_name),
16223                cx,
16224            )
16225            .await?;
16226
16227            editor.update(cx, |editor, cx| {
16228                editor.refresh_document_highlights(cx);
16229            })?;
16230            Ok(())
16231        }))
16232    }
16233
16234    fn take_rename(
16235        &mut self,
16236        moving_cursor: bool,
16237        window: &mut Window,
16238        cx: &mut Context<Self>,
16239    ) -> Option<RenameState> {
16240        let rename = self.pending_rename.take()?;
16241        if rename.editor.focus_handle(cx).is_focused(window) {
16242            window.focus(&self.focus_handle);
16243        }
16244
16245        self.remove_blocks(
16246            [rename.block_id].into_iter().collect(),
16247            Some(Autoscroll::fit()),
16248            cx,
16249        );
16250        self.clear_highlights::<Rename>(cx);
16251        self.show_local_selections = true;
16252
16253        if moving_cursor {
16254            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16255                editor.selections.newest::<usize>(cx).head()
16256            });
16257
16258            // Update the selection to match the position of the selection inside
16259            // the rename editor.
16260            let snapshot = self.buffer.read(cx).read(cx);
16261            let rename_range = rename.range.to_offset(&snapshot);
16262            let cursor_in_editor = snapshot
16263                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16264                .min(rename_range.end);
16265            drop(snapshot);
16266
16267            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16268                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16269            });
16270        } else {
16271            self.refresh_document_highlights(cx);
16272        }
16273
16274        Some(rename)
16275    }
16276
16277    pub fn pending_rename(&self) -> Option<&RenameState> {
16278        self.pending_rename.as_ref()
16279    }
16280
16281    fn format(
16282        &mut self,
16283        _: &Format,
16284        window: &mut Window,
16285        cx: &mut Context<Self>,
16286    ) -> Option<Task<Result<()>>> {
16287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16288
16289        let project = match &self.project {
16290            Some(project) => project.clone(),
16291            None => return None,
16292        };
16293
16294        Some(self.perform_format(
16295            project,
16296            FormatTrigger::Manual,
16297            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16298            window,
16299            cx,
16300        ))
16301    }
16302
16303    fn format_selections(
16304        &mut self,
16305        _: &FormatSelections,
16306        window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) -> Option<Task<Result<()>>> {
16309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16310
16311        let project = match &self.project {
16312            Some(project) => project.clone(),
16313            None => return None,
16314        };
16315
16316        let ranges = self
16317            .selections
16318            .all_adjusted(cx)
16319            .into_iter()
16320            .map(|selection| selection.range())
16321            .collect_vec();
16322
16323        Some(self.perform_format(
16324            project,
16325            FormatTrigger::Manual,
16326            FormatTarget::Ranges(ranges),
16327            window,
16328            cx,
16329        ))
16330    }
16331
16332    fn perform_format(
16333        &mut self,
16334        project: Entity<Project>,
16335        trigger: FormatTrigger,
16336        target: FormatTarget,
16337        window: &mut Window,
16338        cx: &mut Context<Self>,
16339    ) -> Task<Result<()>> {
16340        let buffer = self.buffer.clone();
16341        let (buffers, target) = match target {
16342            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16343            FormatTarget::Ranges(selection_ranges) => {
16344                let multi_buffer = buffer.read(cx);
16345                let snapshot = multi_buffer.read(cx);
16346                let mut buffers = HashSet::default();
16347                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16348                    BTreeMap::new();
16349                for selection_range in selection_ranges {
16350                    for (buffer, buffer_range, _) in
16351                        snapshot.range_to_buffer_ranges(selection_range)
16352                    {
16353                        let buffer_id = buffer.remote_id();
16354                        let start = buffer.anchor_before(buffer_range.start);
16355                        let end = buffer.anchor_after(buffer_range.end);
16356                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16357                        buffer_id_to_ranges
16358                            .entry(buffer_id)
16359                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16360                            .or_insert_with(|| vec![start..end]);
16361                    }
16362                }
16363                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16364            }
16365        };
16366
16367        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16368        let selections_prev = transaction_id_prev
16369            .and_then(|transaction_id_prev| {
16370                // default to selections as they were after the last edit, if we have them,
16371                // instead of how they are now.
16372                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16373                // will take you back to where you made the last edit, instead of staying where you scrolled
16374                self.selection_history
16375                    .transaction(transaction_id_prev)
16376                    .map(|t| t.0.clone())
16377            })
16378            .unwrap_or_else(|| {
16379                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16380                self.selections.disjoint_anchors()
16381            });
16382
16383        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16384        let format = project.update(cx, |project, cx| {
16385            project.format(buffers, target, true, trigger, cx)
16386        });
16387
16388        cx.spawn_in(window, async move |editor, cx| {
16389            let transaction = futures::select_biased! {
16390                transaction = format.log_err().fuse() => transaction,
16391                () = timeout => {
16392                    log::warn!("timed out waiting for formatting");
16393                    None
16394                }
16395            };
16396
16397            buffer
16398                .update(cx, |buffer, cx| {
16399                    if let Some(transaction) = transaction {
16400                        if !buffer.is_singleton() {
16401                            buffer.push_transaction(&transaction.0, cx);
16402                        }
16403                    }
16404                    cx.notify();
16405                })
16406                .ok();
16407
16408            if let Some(transaction_id_now) =
16409                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16410            {
16411                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16412                if has_new_transaction {
16413                    _ = editor.update(cx, |editor, _| {
16414                        editor
16415                            .selection_history
16416                            .insert_transaction(transaction_id_now, selections_prev);
16417                    });
16418                }
16419            }
16420
16421            Ok(())
16422        })
16423    }
16424
16425    fn organize_imports(
16426        &mut self,
16427        _: &OrganizeImports,
16428        window: &mut Window,
16429        cx: &mut Context<Self>,
16430    ) -> Option<Task<Result<()>>> {
16431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16432        let project = match &self.project {
16433            Some(project) => project.clone(),
16434            None => return None,
16435        };
16436        Some(self.perform_code_action_kind(
16437            project,
16438            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16439            window,
16440            cx,
16441        ))
16442    }
16443
16444    fn perform_code_action_kind(
16445        &mut self,
16446        project: Entity<Project>,
16447        kind: CodeActionKind,
16448        window: &mut Window,
16449        cx: &mut Context<Self>,
16450    ) -> Task<Result<()>> {
16451        let buffer = self.buffer.clone();
16452        let buffers = buffer.read(cx).all_buffers();
16453        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16454        let apply_action = project.update(cx, |project, cx| {
16455            project.apply_code_action_kind(buffers, kind, true, cx)
16456        });
16457        cx.spawn_in(window, async move |_, cx| {
16458            let transaction = futures::select_biased! {
16459                () = timeout => {
16460                    log::warn!("timed out waiting for executing code action");
16461                    None
16462                }
16463                transaction = apply_action.log_err().fuse() => transaction,
16464            };
16465            buffer
16466                .update(cx, |buffer, cx| {
16467                    // check if we need this
16468                    if let Some(transaction) = transaction {
16469                        if !buffer.is_singleton() {
16470                            buffer.push_transaction(&transaction.0, cx);
16471                        }
16472                    }
16473                    cx.notify();
16474                })
16475                .ok();
16476            Ok(())
16477        })
16478    }
16479
16480    pub fn restart_language_server(
16481        &mut self,
16482        _: &RestartLanguageServer,
16483        _: &mut Window,
16484        cx: &mut Context<Self>,
16485    ) {
16486        if let Some(project) = self.project.clone() {
16487            self.buffer.update(cx, |multi_buffer, cx| {
16488                project.update(cx, |project, cx| {
16489                    project.restart_language_servers_for_buffers(
16490                        multi_buffer.all_buffers().into_iter().collect(),
16491                        HashSet::default(),
16492                        cx,
16493                    );
16494                });
16495            })
16496        }
16497    }
16498
16499    pub fn stop_language_server(
16500        &mut self,
16501        _: &StopLanguageServer,
16502        _: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        if let Some(project) = self.project.clone() {
16506            self.buffer.update(cx, |multi_buffer, cx| {
16507                project.update(cx, |project, cx| {
16508                    project.stop_language_servers_for_buffers(
16509                        multi_buffer.all_buffers().into_iter().collect(),
16510                        HashSet::default(),
16511                        cx,
16512                    );
16513                    cx.emit(project::Event::RefreshInlayHints);
16514                });
16515            });
16516        }
16517    }
16518
16519    fn cancel_language_server_work(
16520        workspace: &mut Workspace,
16521        _: &actions::CancelLanguageServerWork,
16522        _: &mut Window,
16523        cx: &mut Context<Workspace>,
16524    ) {
16525        let project = workspace.project();
16526        let buffers = workspace
16527            .active_item(cx)
16528            .and_then(|item| item.act_as::<Editor>(cx))
16529            .map_or(HashSet::default(), |editor| {
16530                editor.read(cx).buffer.read(cx).all_buffers()
16531            });
16532        project.update(cx, |project, cx| {
16533            project.cancel_language_server_work_for_buffers(buffers, cx);
16534        });
16535    }
16536
16537    fn show_character_palette(
16538        &mut self,
16539        _: &ShowCharacterPalette,
16540        window: &mut Window,
16541        _: &mut Context<Self>,
16542    ) {
16543        window.show_character_palette();
16544    }
16545
16546    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16547        if !self.diagnostics_enabled() {
16548            return;
16549        }
16550
16551        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16552            let buffer = self.buffer.read(cx).snapshot(cx);
16553            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16554            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16555            let is_valid = buffer
16556                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16557                .any(|entry| {
16558                    entry.diagnostic.is_primary
16559                        && !entry.range.is_empty()
16560                        && entry.range.start == primary_range_start
16561                        && entry.diagnostic.message == active_diagnostics.active_message
16562                });
16563
16564            if !is_valid {
16565                self.dismiss_diagnostics(cx);
16566            }
16567        }
16568    }
16569
16570    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16571        match &self.active_diagnostics {
16572            ActiveDiagnostic::Group(group) => Some(group),
16573            _ => None,
16574        }
16575    }
16576
16577    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16578        if !self.diagnostics_enabled() {
16579            return;
16580        }
16581        self.dismiss_diagnostics(cx);
16582        self.active_diagnostics = ActiveDiagnostic::All;
16583    }
16584
16585    fn activate_diagnostics(
16586        &mut self,
16587        buffer_id: BufferId,
16588        diagnostic: DiagnosticEntry<usize>,
16589        window: &mut Window,
16590        cx: &mut Context<Self>,
16591    ) {
16592        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16593            return;
16594        }
16595        self.dismiss_diagnostics(cx);
16596        let snapshot = self.snapshot(window, cx);
16597        let buffer = self.buffer.read(cx).snapshot(cx);
16598        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16599            return;
16600        };
16601
16602        let diagnostic_group = buffer
16603            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16604            .collect::<Vec<_>>();
16605
16606        let blocks =
16607            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16608
16609        let blocks = self.display_map.update(cx, |display_map, cx| {
16610            display_map.insert_blocks(blocks, cx).into_iter().collect()
16611        });
16612        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16613            active_range: buffer.anchor_before(diagnostic.range.start)
16614                ..buffer.anchor_after(diagnostic.range.end),
16615            active_message: diagnostic.diagnostic.message.clone(),
16616            group_id: diagnostic.diagnostic.group_id,
16617            blocks,
16618        });
16619        cx.notify();
16620    }
16621
16622    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16623        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16624            return;
16625        };
16626
16627        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16628        if let ActiveDiagnostic::Group(group) = prev {
16629            self.display_map.update(cx, |display_map, cx| {
16630                display_map.remove_blocks(group.blocks, cx);
16631            });
16632            cx.notify();
16633        }
16634    }
16635
16636    /// Disable inline diagnostics rendering for this editor.
16637    pub fn disable_inline_diagnostics(&mut self) {
16638        self.inline_diagnostics_enabled = false;
16639        self.inline_diagnostics_update = Task::ready(());
16640        self.inline_diagnostics.clear();
16641    }
16642
16643    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16644        self.diagnostics_enabled = false;
16645        self.dismiss_diagnostics(cx);
16646        self.inline_diagnostics_update = Task::ready(());
16647        self.inline_diagnostics.clear();
16648    }
16649
16650    pub fn diagnostics_enabled(&self) -> bool {
16651        self.diagnostics_enabled && self.mode.is_full()
16652    }
16653
16654    pub fn inline_diagnostics_enabled(&self) -> bool {
16655        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16656    }
16657
16658    pub fn show_inline_diagnostics(&self) -> bool {
16659        self.show_inline_diagnostics
16660    }
16661
16662    pub fn toggle_inline_diagnostics(
16663        &mut self,
16664        _: &ToggleInlineDiagnostics,
16665        window: &mut Window,
16666        cx: &mut Context<Editor>,
16667    ) {
16668        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16669        self.refresh_inline_diagnostics(false, window, cx);
16670    }
16671
16672    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16673        self.diagnostics_max_severity = severity;
16674        self.display_map.update(cx, |display_map, _| {
16675            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16676        });
16677    }
16678
16679    pub fn toggle_diagnostics(
16680        &mut self,
16681        _: &ToggleDiagnostics,
16682        window: &mut Window,
16683        cx: &mut Context<Editor>,
16684    ) {
16685        if !self.diagnostics_enabled() {
16686            return;
16687        }
16688
16689        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16690            EditorSettings::get_global(cx)
16691                .diagnostics_max_severity
16692                .filter(|severity| severity != &DiagnosticSeverity::Off)
16693                .unwrap_or(DiagnosticSeverity::Hint)
16694        } else {
16695            DiagnosticSeverity::Off
16696        };
16697        self.set_max_diagnostics_severity(new_severity, cx);
16698        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16699            self.active_diagnostics = ActiveDiagnostic::None;
16700            self.inline_diagnostics_update = Task::ready(());
16701            self.inline_diagnostics.clear();
16702        } else {
16703            self.refresh_inline_diagnostics(false, window, cx);
16704        }
16705
16706        cx.notify();
16707    }
16708
16709    pub fn toggle_minimap(
16710        &mut self,
16711        _: &ToggleMinimap,
16712        window: &mut Window,
16713        cx: &mut Context<Editor>,
16714    ) {
16715        if self.supports_minimap(cx) {
16716            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16717        }
16718    }
16719
16720    fn refresh_inline_diagnostics(
16721        &mut self,
16722        debounce: bool,
16723        window: &mut Window,
16724        cx: &mut Context<Self>,
16725    ) {
16726        let max_severity = ProjectSettings::get_global(cx)
16727            .diagnostics
16728            .inline
16729            .max_severity
16730            .unwrap_or(self.diagnostics_max_severity);
16731
16732        if !self.inline_diagnostics_enabled()
16733            || !self.show_inline_diagnostics
16734            || max_severity == DiagnosticSeverity::Off
16735        {
16736            self.inline_diagnostics_update = Task::ready(());
16737            self.inline_diagnostics.clear();
16738            return;
16739        }
16740
16741        let debounce_ms = ProjectSettings::get_global(cx)
16742            .diagnostics
16743            .inline
16744            .update_debounce_ms;
16745        let debounce = if debounce && debounce_ms > 0 {
16746            Some(Duration::from_millis(debounce_ms))
16747        } else {
16748            None
16749        };
16750        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16751            if let Some(debounce) = debounce {
16752                cx.background_executor().timer(debounce).await;
16753            }
16754            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16755                editor
16756                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16757                    .ok()
16758            }) else {
16759                return;
16760            };
16761
16762            let new_inline_diagnostics = cx
16763                .background_spawn(async move {
16764                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16765                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16766                        let message = diagnostic_entry
16767                            .diagnostic
16768                            .message
16769                            .split_once('\n')
16770                            .map(|(line, _)| line)
16771                            .map(SharedString::new)
16772                            .unwrap_or_else(|| {
16773                                SharedString::from(diagnostic_entry.diagnostic.message)
16774                            });
16775                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16776                        let (Ok(i) | Err(i)) = inline_diagnostics
16777                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16778                        inline_diagnostics.insert(
16779                            i,
16780                            (
16781                                start_anchor,
16782                                InlineDiagnostic {
16783                                    message,
16784                                    group_id: diagnostic_entry.diagnostic.group_id,
16785                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16786                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16787                                    severity: diagnostic_entry.diagnostic.severity,
16788                                },
16789                            ),
16790                        );
16791                    }
16792                    inline_diagnostics
16793                })
16794                .await;
16795
16796            editor
16797                .update(cx, |editor, cx| {
16798                    editor.inline_diagnostics = new_inline_diagnostics;
16799                    cx.notify();
16800                })
16801                .ok();
16802        });
16803    }
16804
16805    fn pull_diagnostics(
16806        &mut self,
16807        buffer_id: Option<BufferId>,
16808        window: &Window,
16809        cx: &mut Context<Self>,
16810    ) -> Option<()> {
16811        if !self.mode().is_full() {
16812            return None;
16813        }
16814        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16815            .diagnostics
16816            .lsp_pull_diagnostics;
16817        if !pull_diagnostics_settings.enabled {
16818            return None;
16819        }
16820        let project = self.project.as_ref()?.downgrade();
16821        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16822        let mut buffers = self.buffer.read(cx).all_buffers();
16823        if let Some(buffer_id) = buffer_id {
16824            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16825        }
16826
16827        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16828            cx.background_executor().timer(debounce).await;
16829
16830            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16831                buffers
16832                    .into_iter()
16833                    .filter_map(|buffer| {
16834                        project
16835                            .update(cx, |project, cx| {
16836                                project.lsp_store().update(cx, |lsp_store, cx| {
16837                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16838                                })
16839                            })
16840                            .ok()
16841                    })
16842                    .collect::<FuturesUnordered<_>>()
16843            }) else {
16844                return;
16845            };
16846
16847            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16848                match pull_task {
16849                    Ok(()) => {
16850                        if editor
16851                            .update_in(cx, |editor, window, cx| {
16852                                editor.update_diagnostics_state(window, cx);
16853                            })
16854                            .is_err()
16855                        {
16856                            return;
16857                        }
16858                    }
16859                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16860                }
16861            }
16862        });
16863
16864        Some(())
16865    }
16866
16867    pub fn set_selections_from_remote(
16868        &mut self,
16869        selections: Vec<Selection<Anchor>>,
16870        pending_selection: Option<Selection<Anchor>>,
16871        window: &mut Window,
16872        cx: &mut Context<Self>,
16873    ) {
16874        let old_cursor_position = self.selections.newest_anchor().head();
16875        self.selections.change_with(cx, |s| {
16876            s.select_anchors(selections);
16877            if let Some(pending_selection) = pending_selection {
16878                s.set_pending(pending_selection, SelectMode::Character);
16879            } else {
16880                s.clear_pending();
16881            }
16882        });
16883        self.selections_did_change(
16884            false,
16885            &old_cursor_position,
16886            SelectionEffects::default(),
16887            window,
16888            cx,
16889        );
16890    }
16891
16892    pub fn transact(
16893        &mut self,
16894        window: &mut Window,
16895        cx: &mut Context<Self>,
16896        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16897    ) -> Option<TransactionId> {
16898        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16899            this.start_transaction_at(Instant::now(), window, cx);
16900            update(this, window, cx);
16901            this.end_transaction_at(Instant::now(), cx)
16902        })
16903    }
16904
16905    pub fn start_transaction_at(
16906        &mut self,
16907        now: Instant,
16908        window: &mut Window,
16909        cx: &mut Context<Self>,
16910    ) {
16911        self.end_selection(window, cx);
16912        if let Some(tx_id) = self
16913            .buffer
16914            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16915        {
16916            self.selection_history
16917                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16918            cx.emit(EditorEvent::TransactionBegun {
16919                transaction_id: tx_id,
16920            })
16921        }
16922    }
16923
16924    pub fn end_transaction_at(
16925        &mut self,
16926        now: Instant,
16927        cx: &mut Context<Self>,
16928    ) -> Option<TransactionId> {
16929        if let Some(transaction_id) = self
16930            .buffer
16931            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16932        {
16933            if let Some((_, end_selections)) =
16934                self.selection_history.transaction_mut(transaction_id)
16935            {
16936                *end_selections = Some(self.selections.disjoint_anchors());
16937            } else {
16938                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16939            }
16940
16941            cx.emit(EditorEvent::Edited { transaction_id });
16942            Some(transaction_id)
16943        } else {
16944            None
16945        }
16946    }
16947
16948    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16949        if self.selection_mark_mode {
16950            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16951                s.move_with(|_, sel| {
16952                    sel.collapse_to(sel.head(), SelectionGoal::None);
16953                });
16954            })
16955        }
16956        self.selection_mark_mode = true;
16957        cx.notify();
16958    }
16959
16960    pub fn swap_selection_ends(
16961        &mut self,
16962        _: &actions::SwapSelectionEnds,
16963        window: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16967            s.move_with(|_, sel| {
16968                if sel.start != sel.end {
16969                    sel.reversed = !sel.reversed
16970                }
16971            });
16972        });
16973        self.request_autoscroll(Autoscroll::newest(), cx);
16974        cx.notify();
16975    }
16976
16977    pub fn toggle_fold(
16978        &mut self,
16979        _: &actions::ToggleFold,
16980        window: &mut Window,
16981        cx: &mut Context<Self>,
16982    ) {
16983        if self.is_singleton(cx) {
16984            let selection = self.selections.newest::<Point>(cx);
16985
16986            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16987            let range = if selection.is_empty() {
16988                let point = selection.head().to_display_point(&display_map);
16989                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16990                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16991                    .to_point(&display_map);
16992                start..end
16993            } else {
16994                selection.range()
16995            };
16996            if display_map.folds_in_range(range).next().is_some() {
16997                self.unfold_lines(&Default::default(), window, cx)
16998            } else {
16999                self.fold(&Default::default(), window, cx)
17000            }
17001        } else {
17002            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17003            let buffer_ids: HashSet<_> = self
17004                .selections
17005                .disjoint_anchor_ranges()
17006                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17007                .collect();
17008
17009            let should_unfold = buffer_ids
17010                .iter()
17011                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17012
17013            for buffer_id in buffer_ids {
17014                if should_unfold {
17015                    self.unfold_buffer(buffer_id, cx);
17016                } else {
17017                    self.fold_buffer(buffer_id, cx);
17018                }
17019            }
17020        }
17021    }
17022
17023    pub fn toggle_fold_recursive(
17024        &mut self,
17025        _: &actions::ToggleFoldRecursive,
17026        window: &mut Window,
17027        cx: &mut Context<Self>,
17028    ) {
17029        let selection = self.selections.newest::<Point>(cx);
17030
17031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17032        let range = if selection.is_empty() {
17033            let point = selection.head().to_display_point(&display_map);
17034            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17035            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17036                .to_point(&display_map);
17037            start..end
17038        } else {
17039            selection.range()
17040        };
17041        if display_map.folds_in_range(range).next().is_some() {
17042            self.unfold_recursive(&Default::default(), window, cx)
17043        } else {
17044            self.fold_recursive(&Default::default(), window, cx)
17045        }
17046    }
17047
17048    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17049        if self.is_singleton(cx) {
17050            let mut to_fold = Vec::new();
17051            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17052            let selections = self.selections.all_adjusted(cx);
17053
17054            for selection in selections {
17055                let range = selection.range().sorted();
17056                let buffer_start_row = range.start.row;
17057
17058                if range.start.row != range.end.row {
17059                    let mut found = false;
17060                    let mut row = range.start.row;
17061                    while row <= range.end.row {
17062                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17063                        {
17064                            found = true;
17065                            row = crease.range().end.row + 1;
17066                            to_fold.push(crease);
17067                        } else {
17068                            row += 1
17069                        }
17070                    }
17071                    if found {
17072                        continue;
17073                    }
17074                }
17075
17076                for row in (0..=range.start.row).rev() {
17077                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17078                        if crease.range().end.row >= buffer_start_row {
17079                            to_fold.push(crease);
17080                            if row <= range.start.row {
17081                                break;
17082                            }
17083                        }
17084                    }
17085                }
17086            }
17087
17088            self.fold_creases(to_fold, true, window, cx);
17089        } else {
17090            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17091            let buffer_ids = self
17092                .selections
17093                .disjoint_anchor_ranges()
17094                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17095                .collect::<HashSet<_>>();
17096            for buffer_id in buffer_ids {
17097                self.fold_buffer(buffer_id, cx);
17098            }
17099        }
17100    }
17101
17102    pub fn toggle_fold_all(
17103        &mut self,
17104        _: &actions::ToggleFoldAll,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) {
17108        if self.buffer.read(cx).is_singleton() {
17109            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17110            let has_folds = display_map
17111                .folds_in_range(0..display_map.buffer_snapshot.len())
17112                .next()
17113                .is_some();
17114
17115            if has_folds {
17116                self.unfold_all(&actions::UnfoldAll, window, cx);
17117            } else {
17118                self.fold_all(&actions::FoldAll, window, cx);
17119            }
17120        } else {
17121            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17122            let should_unfold = buffer_ids
17123                .iter()
17124                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17125
17126            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17127                editor
17128                    .update_in(cx, |editor, _, cx| {
17129                        for buffer_id in buffer_ids {
17130                            if should_unfold {
17131                                editor.unfold_buffer(buffer_id, cx);
17132                            } else {
17133                                editor.fold_buffer(buffer_id, cx);
17134                            }
17135                        }
17136                    })
17137                    .ok();
17138            });
17139        }
17140    }
17141
17142    fn fold_at_level(
17143        &mut self,
17144        fold_at: &FoldAtLevel,
17145        window: &mut Window,
17146        cx: &mut Context<Self>,
17147    ) {
17148        if !self.buffer.read(cx).is_singleton() {
17149            return;
17150        }
17151
17152        let fold_at_level = fold_at.0;
17153        let snapshot = self.buffer.read(cx).snapshot(cx);
17154        let mut to_fold = Vec::new();
17155        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17156
17157        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17158            while start_row < end_row {
17159                match self
17160                    .snapshot(window, cx)
17161                    .crease_for_buffer_row(MultiBufferRow(start_row))
17162                {
17163                    Some(crease) => {
17164                        let nested_start_row = crease.range().start.row + 1;
17165                        let nested_end_row = crease.range().end.row;
17166
17167                        if current_level < fold_at_level {
17168                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17169                        } else if current_level == fold_at_level {
17170                            to_fold.push(crease);
17171                        }
17172
17173                        start_row = nested_end_row + 1;
17174                    }
17175                    None => start_row += 1,
17176                }
17177            }
17178        }
17179
17180        self.fold_creases(to_fold, true, window, cx);
17181    }
17182
17183    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17184        if self.buffer.read(cx).is_singleton() {
17185            let mut fold_ranges = Vec::new();
17186            let snapshot = self.buffer.read(cx).snapshot(cx);
17187
17188            for row in 0..snapshot.max_row().0 {
17189                if let Some(foldable_range) = self
17190                    .snapshot(window, cx)
17191                    .crease_for_buffer_row(MultiBufferRow(row))
17192                {
17193                    fold_ranges.push(foldable_range);
17194                }
17195            }
17196
17197            self.fold_creases(fold_ranges, true, window, cx);
17198        } else {
17199            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17200                editor
17201                    .update_in(cx, |editor, _, cx| {
17202                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17203                            editor.fold_buffer(buffer_id, cx);
17204                        }
17205                    })
17206                    .ok();
17207            });
17208        }
17209    }
17210
17211    pub fn fold_function_bodies(
17212        &mut self,
17213        _: &actions::FoldFunctionBodies,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        let snapshot = self.buffer.read(cx).snapshot(cx);
17218
17219        let ranges = snapshot
17220            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17221            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17222            .collect::<Vec<_>>();
17223
17224        let creases = ranges
17225            .into_iter()
17226            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17227            .collect();
17228
17229        self.fold_creases(creases, true, window, cx);
17230    }
17231
17232    pub fn fold_recursive(
17233        &mut self,
17234        _: &actions::FoldRecursive,
17235        window: &mut Window,
17236        cx: &mut Context<Self>,
17237    ) {
17238        let mut to_fold = Vec::new();
17239        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17240        let selections = self.selections.all_adjusted(cx);
17241
17242        for selection in selections {
17243            let range = selection.range().sorted();
17244            let buffer_start_row = range.start.row;
17245
17246            if range.start.row != range.end.row {
17247                let mut found = false;
17248                for row in range.start.row..=range.end.row {
17249                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17250                        found = true;
17251                        to_fold.push(crease);
17252                    }
17253                }
17254                if found {
17255                    continue;
17256                }
17257            }
17258
17259            for row in (0..=range.start.row).rev() {
17260                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17261                    if crease.range().end.row >= buffer_start_row {
17262                        to_fold.push(crease);
17263                    } else {
17264                        break;
17265                    }
17266                }
17267            }
17268        }
17269
17270        self.fold_creases(to_fold, true, window, cx);
17271    }
17272
17273    pub fn fold_at(
17274        &mut self,
17275        buffer_row: MultiBufferRow,
17276        window: &mut Window,
17277        cx: &mut Context<Self>,
17278    ) {
17279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17280
17281        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17282            let autoscroll = self
17283                .selections
17284                .all::<Point>(cx)
17285                .iter()
17286                .any(|selection| crease.range().overlaps(&selection.range()));
17287
17288            self.fold_creases(vec![crease], autoscroll, window, cx);
17289        }
17290    }
17291
17292    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17293        if self.is_singleton(cx) {
17294            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17295            let buffer = &display_map.buffer_snapshot;
17296            let selections = self.selections.all::<Point>(cx);
17297            let ranges = selections
17298                .iter()
17299                .map(|s| {
17300                    let range = s.display_range(&display_map).sorted();
17301                    let mut start = range.start.to_point(&display_map);
17302                    let mut end = range.end.to_point(&display_map);
17303                    start.column = 0;
17304                    end.column = buffer.line_len(MultiBufferRow(end.row));
17305                    start..end
17306                })
17307                .collect::<Vec<_>>();
17308
17309            self.unfold_ranges(&ranges, true, true, cx);
17310        } else {
17311            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17312            let buffer_ids = self
17313                .selections
17314                .disjoint_anchor_ranges()
17315                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17316                .collect::<HashSet<_>>();
17317            for buffer_id in buffer_ids {
17318                self.unfold_buffer(buffer_id, cx);
17319            }
17320        }
17321    }
17322
17323    pub fn unfold_recursive(
17324        &mut self,
17325        _: &UnfoldRecursive,
17326        _window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) {
17329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17330        let selections = self.selections.all::<Point>(cx);
17331        let ranges = selections
17332            .iter()
17333            .map(|s| {
17334                let mut range = s.display_range(&display_map).sorted();
17335                *range.start.column_mut() = 0;
17336                *range.end.column_mut() = display_map.line_len(range.end.row());
17337                let start = range.start.to_point(&display_map);
17338                let end = range.end.to_point(&display_map);
17339                start..end
17340            })
17341            .collect::<Vec<_>>();
17342
17343        self.unfold_ranges(&ranges, true, true, cx);
17344    }
17345
17346    pub fn unfold_at(
17347        &mut self,
17348        buffer_row: MultiBufferRow,
17349        _window: &mut Window,
17350        cx: &mut Context<Self>,
17351    ) {
17352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17353
17354        let intersection_range = Point::new(buffer_row.0, 0)
17355            ..Point::new(
17356                buffer_row.0,
17357                display_map.buffer_snapshot.line_len(buffer_row),
17358            );
17359
17360        let autoscroll = self
17361            .selections
17362            .all::<Point>(cx)
17363            .iter()
17364            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17365
17366        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17367    }
17368
17369    pub fn unfold_all(
17370        &mut self,
17371        _: &actions::UnfoldAll,
17372        _window: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        if self.buffer.read(cx).is_singleton() {
17376            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17377            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17378        } else {
17379            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17380                editor
17381                    .update(cx, |editor, cx| {
17382                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17383                            editor.unfold_buffer(buffer_id, cx);
17384                        }
17385                    })
17386                    .ok();
17387            });
17388        }
17389    }
17390
17391    pub fn fold_selected_ranges(
17392        &mut self,
17393        _: &FoldSelectedRanges,
17394        window: &mut Window,
17395        cx: &mut Context<Self>,
17396    ) {
17397        let selections = self.selections.all_adjusted(cx);
17398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17399        let ranges = selections
17400            .into_iter()
17401            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17402            .collect::<Vec<_>>();
17403        self.fold_creases(ranges, true, window, cx);
17404    }
17405
17406    pub fn fold_ranges<T: ToOffset + Clone>(
17407        &mut self,
17408        ranges: Vec<Range<T>>,
17409        auto_scroll: bool,
17410        window: &mut Window,
17411        cx: &mut Context<Self>,
17412    ) {
17413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17414        let ranges = ranges
17415            .into_iter()
17416            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17417            .collect::<Vec<_>>();
17418        self.fold_creases(ranges, auto_scroll, window, cx);
17419    }
17420
17421    pub fn fold_creases<T: ToOffset + Clone>(
17422        &mut self,
17423        creases: Vec<Crease<T>>,
17424        auto_scroll: bool,
17425        _window: &mut Window,
17426        cx: &mut Context<Self>,
17427    ) {
17428        if creases.is_empty() {
17429            return;
17430        }
17431
17432        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17433
17434        if auto_scroll {
17435            self.request_autoscroll(Autoscroll::fit(), cx);
17436        }
17437
17438        cx.notify();
17439
17440        self.scrollbar_marker_state.dirty = true;
17441        self.folds_did_change(cx);
17442    }
17443
17444    /// Removes any folds whose ranges intersect any of the given ranges.
17445    pub fn unfold_ranges<T: ToOffset + Clone>(
17446        &mut self,
17447        ranges: &[Range<T>],
17448        inclusive: bool,
17449        auto_scroll: bool,
17450        cx: &mut Context<Self>,
17451    ) {
17452        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17453            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17454        });
17455        self.folds_did_change(cx);
17456    }
17457
17458    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17459        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17460            return;
17461        }
17462        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17463        self.display_map.update(cx, |display_map, cx| {
17464            display_map.fold_buffers([buffer_id], cx)
17465        });
17466        cx.emit(EditorEvent::BufferFoldToggled {
17467            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17468            folded: true,
17469        });
17470        cx.notify();
17471    }
17472
17473    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17474        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17475            return;
17476        }
17477        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17478        self.display_map.update(cx, |display_map, cx| {
17479            display_map.unfold_buffers([buffer_id], cx);
17480        });
17481        cx.emit(EditorEvent::BufferFoldToggled {
17482            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17483            folded: false,
17484        });
17485        cx.notify();
17486    }
17487
17488    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17489        self.display_map.read(cx).is_buffer_folded(buffer)
17490    }
17491
17492    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17493        self.display_map.read(cx).folded_buffers()
17494    }
17495
17496    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17497        self.display_map.update(cx, |display_map, cx| {
17498            display_map.disable_header_for_buffer(buffer_id, cx);
17499        });
17500        cx.notify();
17501    }
17502
17503    /// Removes any folds with the given ranges.
17504    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17505        &mut self,
17506        ranges: &[Range<T>],
17507        type_id: TypeId,
17508        auto_scroll: bool,
17509        cx: &mut Context<Self>,
17510    ) {
17511        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17512            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17513        });
17514        self.folds_did_change(cx);
17515    }
17516
17517    fn remove_folds_with<T: ToOffset + Clone>(
17518        &mut self,
17519        ranges: &[Range<T>],
17520        auto_scroll: bool,
17521        cx: &mut Context<Self>,
17522        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17523    ) {
17524        if ranges.is_empty() {
17525            return;
17526        }
17527
17528        let mut buffers_affected = HashSet::default();
17529        let multi_buffer = self.buffer().read(cx);
17530        for range in ranges {
17531            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17532                buffers_affected.insert(buffer.read(cx).remote_id());
17533            };
17534        }
17535
17536        self.display_map.update(cx, update);
17537
17538        if auto_scroll {
17539            self.request_autoscroll(Autoscroll::fit(), cx);
17540        }
17541
17542        cx.notify();
17543        self.scrollbar_marker_state.dirty = true;
17544        self.active_indent_guides_state.dirty = true;
17545    }
17546
17547    pub fn update_renderer_widths(
17548        &mut self,
17549        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17550        cx: &mut Context<Self>,
17551    ) -> bool {
17552        self.display_map
17553            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17554    }
17555
17556    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17557        self.display_map.read(cx).fold_placeholder.clone()
17558    }
17559
17560    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17561        self.buffer.update(cx, |buffer, cx| {
17562            buffer.set_all_diff_hunks_expanded(cx);
17563        });
17564    }
17565
17566    pub fn expand_all_diff_hunks(
17567        &mut self,
17568        _: &ExpandAllDiffHunks,
17569        _window: &mut Window,
17570        cx: &mut Context<Self>,
17571    ) {
17572        self.buffer.update(cx, |buffer, cx| {
17573            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17574        });
17575    }
17576
17577    pub fn toggle_selected_diff_hunks(
17578        &mut self,
17579        _: &ToggleSelectedDiffHunks,
17580        _window: &mut Window,
17581        cx: &mut Context<Self>,
17582    ) {
17583        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17584        self.toggle_diff_hunks_in_ranges(ranges, cx);
17585    }
17586
17587    pub fn diff_hunks_in_ranges<'a>(
17588        &'a self,
17589        ranges: &'a [Range<Anchor>],
17590        buffer: &'a MultiBufferSnapshot,
17591    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17592        ranges.iter().flat_map(move |range| {
17593            let end_excerpt_id = range.end.excerpt_id;
17594            let range = range.to_point(buffer);
17595            let mut peek_end = range.end;
17596            if range.end.row < buffer.max_row().0 {
17597                peek_end = Point::new(range.end.row + 1, 0);
17598            }
17599            buffer
17600                .diff_hunks_in_range(range.start..peek_end)
17601                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17602        })
17603    }
17604
17605    pub fn has_stageable_diff_hunks_in_ranges(
17606        &self,
17607        ranges: &[Range<Anchor>],
17608        snapshot: &MultiBufferSnapshot,
17609    ) -> bool {
17610        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17611        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17612    }
17613
17614    pub fn toggle_staged_selected_diff_hunks(
17615        &mut self,
17616        _: &::git::ToggleStaged,
17617        _: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        let snapshot = self.buffer.read(cx).snapshot(cx);
17621        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17622        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17623        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17624    }
17625
17626    pub fn set_render_diff_hunk_controls(
17627        &mut self,
17628        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17629        cx: &mut Context<Self>,
17630    ) {
17631        self.render_diff_hunk_controls = render_diff_hunk_controls;
17632        cx.notify();
17633    }
17634
17635    pub fn stage_and_next(
17636        &mut self,
17637        _: &::git::StageAndNext,
17638        window: &mut Window,
17639        cx: &mut Context<Self>,
17640    ) {
17641        self.do_stage_or_unstage_and_next(true, window, cx);
17642    }
17643
17644    pub fn unstage_and_next(
17645        &mut self,
17646        _: &::git::UnstageAndNext,
17647        window: &mut Window,
17648        cx: &mut Context<Self>,
17649    ) {
17650        self.do_stage_or_unstage_and_next(false, window, cx);
17651    }
17652
17653    pub fn stage_or_unstage_diff_hunks(
17654        &mut self,
17655        stage: bool,
17656        ranges: Vec<Range<Anchor>>,
17657        cx: &mut Context<Self>,
17658    ) {
17659        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17660        cx.spawn(async move |this, cx| {
17661            task.await?;
17662            this.update(cx, |this, cx| {
17663                let snapshot = this.buffer.read(cx).snapshot(cx);
17664                let chunk_by = this
17665                    .diff_hunks_in_ranges(&ranges, &snapshot)
17666                    .chunk_by(|hunk| hunk.buffer_id);
17667                for (buffer_id, hunks) in &chunk_by {
17668                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17669                }
17670            })
17671        })
17672        .detach_and_log_err(cx);
17673    }
17674
17675    fn save_buffers_for_ranges_if_needed(
17676        &mut self,
17677        ranges: &[Range<Anchor>],
17678        cx: &mut Context<Editor>,
17679    ) -> Task<Result<()>> {
17680        let multibuffer = self.buffer.read(cx);
17681        let snapshot = multibuffer.read(cx);
17682        let buffer_ids: HashSet<_> = ranges
17683            .iter()
17684            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17685            .collect();
17686        drop(snapshot);
17687
17688        let mut buffers = HashSet::default();
17689        for buffer_id in buffer_ids {
17690            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17691                let buffer = buffer_entity.read(cx);
17692                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17693                {
17694                    buffers.insert(buffer_entity);
17695                }
17696            }
17697        }
17698
17699        if let Some(project) = &self.project {
17700            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17701        } else {
17702            Task::ready(Ok(()))
17703        }
17704    }
17705
17706    fn do_stage_or_unstage_and_next(
17707        &mut self,
17708        stage: bool,
17709        window: &mut Window,
17710        cx: &mut Context<Self>,
17711    ) {
17712        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17713
17714        if ranges.iter().any(|range| range.start != range.end) {
17715            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17716            return;
17717        }
17718
17719        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17720        let snapshot = self.snapshot(window, cx);
17721        let position = self.selections.newest::<Point>(cx).head();
17722        let mut row = snapshot
17723            .buffer_snapshot
17724            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17725            .find(|hunk| hunk.row_range.start.0 > position.row)
17726            .map(|hunk| hunk.row_range.start);
17727
17728        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17729        // Outside of the project diff editor, wrap around to the beginning.
17730        if !all_diff_hunks_expanded {
17731            row = row.or_else(|| {
17732                snapshot
17733                    .buffer_snapshot
17734                    .diff_hunks_in_range(Point::zero()..position)
17735                    .find(|hunk| hunk.row_range.end.0 < position.row)
17736                    .map(|hunk| hunk.row_range.start)
17737            });
17738        }
17739
17740        if let Some(row) = row {
17741            let destination = Point::new(row.0, 0);
17742            let autoscroll = Autoscroll::center();
17743
17744            self.unfold_ranges(&[destination..destination], false, false, cx);
17745            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17746                s.select_ranges([destination..destination]);
17747            });
17748        }
17749    }
17750
17751    fn do_stage_or_unstage(
17752        &self,
17753        stage: bool,
17754        buffer_id: BufferId,
17755        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17756        cx: &mut App,
17757    ) -> Option<()> {
17758        let project = self.project.as_ref()?;
17759        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17760        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17761        let buffer_snapshot = buffer.read(cx).snapshot();
17762        let file_exists = buffer_snapshot
17763            .file()
17764            .is_some_and(|file| file.disk_state().exists());
17765        diff.update(cx, |diff, cx| {
17766            diff.stage_or_unstage_hunks(
17767                stage,
17768                &hunks
17769                    .map(|hunk| buffer_diff::DiffHunk {
17770                        buffer_range: hunk.buffer_range,
17771                        diff_base_byte_range: hunk.diff_base_byte_range,
17772                        secondary_status: hunk.secondary_status,
17773                        range: Point::zero()..Point::zero(), // unused
17774                    })
17775                    .collect::<Vec<_>>(),
17776                &buffer_snapshot,
17777                file_exists,
17778                cx,
17779            )
17780        });
17781        None
17782    }
17783
17784    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17785        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17786        self.buffer
17787            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17788    }
17789
17790    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17791        self.buffer.update(cx, |buffer, cx| {
17792            let ranges = vec![Anchor::min()..Anchor::max()];
17793            if !buffer.all_diff_hunks_expanded()
17794                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17795            {
17796                buffer.collapse_diff_hunks(ranges, cx);
17797                true
17798            } else {
17799                false
17800            }
17801        })
17802    }
17803
17804    fn toggle_diff_hunks_in_ranges(
17805        &mut self,
17806        ranges: Vec<Range<Anchor>>,
17807        cx: &mut Context<Editor>,
17808    ) {
17809        self.buffer.update(cx, |buffer, cx| {
17810            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17811            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17812        })
17813    }
17814
17815    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17816        self.buffer.update(cx, |buffer, cx| {
17817            let snapshot = buffer.snapshot(cx);
17818            let excerpt_id = range.end.excerpt_id;
17819            let point_range = range.to_point(&snapshot);
17820            let expand = !buffer.single_hunk_is_expanded(range, cx);
17821            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17822        })
17823    }
17824
17825    pub(crate) fn apply_all_diff_hunks(
17826        &mut self,
17827        _: &ApplyAllDiffHunks,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) {
17831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17832
17833        let buffers = self.buffer.read(cx).all_buffers();
17834        for branch_buffer in buffers {
17835            branch_buffer.update(cx, |branch_buffer, cx| {
17836                branch_buffer.merge_into_base(Vec::new(), cx);
17837            });
17838        }
17839
17840        if let Some(project) = self.project.clone() {
17841            self.save(
17842                SaveOptions {
17843                    format: true,
17844                    autosave: false,
17845                },
17846                project,
17847                window,
17848                cx,
17849            )
17850            .detach_and_log_err(cx);
17851        }
17852    }
17853
17854    pub(crate) fn apply_selected_diff_hunks(
17855        &mut self,
17856        _: &ApplyDiffHunk,
17857        window: &mut Window,
17858        cx: &mut Context<Self>,
17859    ) {
17860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17861        let snapshot = self.snapshot(window, cx);
17862        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17863        let mut ranges_by_buffer = HashMap::default();
17864        self.transact(window, cx, |editor, _window, cx| {
17865            for hunk in hunks {
17866                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17867                    ranges_by_buffer
17868                        .entry(buffer.clone())
17869                        .or_insert_with(Vec::new)
17870                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17871                }
17872            }
17873
17874            for (buffer, ranges) in ranges_by_buffer {
17875                buffer.update(cx, |buffer, cx| {
17876                    buffer.merge_into_base(ranges, cx);
17877                });
17878            }
17879        });
17880
17881        if let Some(project) = self.project.clone() {
17882            self.save(
17883                SaveOptions {
17884                    format: true,
17885                    autosave: false,
17886                },
17887                project,
17888                window,
17889                cx,
17890            )
17891            .detach_and_log_err(cx);
17892        }
17893    }
17894
17895    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17896        if hovered != self.gutter_hovered {
17897            self.gutter_hovered = hovered;
17898            cx.notify();
17899        }
17900    }
17901
17902    pub fn insert_blocks(
17903        &mut self,
17904        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17905        autoscroll: Option<Autoscroll>,
17906        cx: &mut Context<Self>,
17907    ) -> Vec<CustomBlockId> {
17908        let blocks = self
17909            .display_map
17910            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17911        if let Some(autoscroll) = autoscroll {
17912            self.request_autoscroll(autoscroll, cx);
17913        }
17914        cx.notify();
17915        blocks
17916    }
17917
17918    pub fn resize_blocks(
17919        &mut self,
17920        heights: HashMap<CustomBlockId, u32>,
17921        autoscroll: Option<Autoscroll>,
17922        cx: &mut Context<Self>,
17923    ) {
17924        self.display_map
17925            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17926        if let Some(autoscroll) = autoscroll {
17927            self.request_autoscroll(autoscroll, cx);
17928        }
17929        cx.notify();
17930    }
17931
17932    pub fn replace_blocks(
17933        &mut self,
17934        renderers: HashMap<CustomBlockId, RenderBlock>,
17935        autoscroll: Option<Autoscroll>,
17936        cx: &mut Context<Self>,
17937    ) {
17938        self.display_map
17939            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17940        if let Some(autoscroll) = autoscroll {
17941            self.request_autoscroll(autoscroll, cx);
17942        }
17943        cx.notify();
17944    }
17945
17946    pub fn remove_blocks(
17947        &mut self,
17948        block_ids: HashSet<CustomBlockId>,
17949        autoscroll: Option<Autoscroll>,
17950        cx: &mut Context<Self>,
17951    ) {
17952        self.display_map.update(cx, |display_map, cx| {
17953            display_map.remove_blocks(block_ids, cx)
17954        });
17955        if let Some(autoscroll) = autoscroll {
17956            self.request_autoscroll(autoscroll, cx);
17957        }
17958        cx.notify();
17959    }
17960
17961    pub fn row_for_block(
17962        &self,
17963        block_id: CustomBlockId,
17964        cx: &mut Context<Self>,
17965    ) -> Option<DisplayRow> {
17966        self.display_map
17967            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17968    }
17969
17970    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17971        self.focused_block = Some(focused_block);
17972    }
17973
17974    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17975        self.focused_block.take()
17976    }
17977
17978    pub fn insert_creases(
17979        &mut self,
17980        creases: impl IntoIterator<Item = Crease<Anchor>>,
17981        cx: &mut Context<Self>,
17982    ) -> Vec<CreaseId> {
17983        self.display_map
17984            .update(cx, |map, cx| map.insert_creases(creases, cx))
17985    }
17986
17987    pub fn remove_creases(
17988        &mut self,
17989        ids: impl IntoIterator<Item = CreaseId>,
17990        cx: &mut Context<Self>,
17991    ) -> Vec<(CreaseId, Range<Anchor>)> {
17992        self.display_map
17993            .update(cx, |map, cx| map.remove_creases(ids, cx))
17994    }
17995
17996    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17997        self.display_map
17998            .update(cx, |map, cx| map.snapshot(cx))
17999            .longest_row()
18000    }
18001
18002    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18003        self.display_map
18004            .update(cx, |map, cx| map.snapshot(cx))
18005            .max_point()
18006    }
18007
18008    pub fn text(&self, cx: &App) -> String {
18009        self.buffer.read(cx).read(cx).text()
18010    }
18011
18012    pub fn is_empty(&self, cx: &App) -> bool {
18013        self.buffer.read(cx).read(cx).is_empty()
18014    }
18015
18016    pub fn text_option(&self, cx: &App) -> Option<String> {
18017        let text = self.text(cx);
18018        let text = text.trim();
18019
18020        if text.is_empty() {
18021            return None;
18022        }
18023
18024        Some(text.to_string())
18025    }
18026
18027    pub fn set_text(
18028        &mut self,
18029        text: impl Into<Arc<str>>,
18030        window: &mut Window,
18031        cx: &mut Context<Self>,
18032    ) {
18033        self.transact(window, cx, |this, _, cx| {
18034            this.buffer
18035                .read(cx)
18036                .as_singleton()
18037                .expect("you can only call set_text on editors for singleton buffers")
18038                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18039        });
18040    }
18041
18042    pub fn display_text(&self, cx: &mut App) -> String {
18043        self.display_map
18044            .update(cx, |map, cx| map.snapshot(cx))
18045            .text()
18046    }
18047
18048    fn create_minimap(
18049        &self,
18050        minimap_settings: MinimapSettings,
18051        window: &mut Window,
18052        cx: &mut Context<Self>,
18053    ) -> Option<Entity<Self>> {
18054        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18055            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18056    }
18057
18058    fn initialize_new_minimap(
18059        &self,
18060        minimap_settings: MinimapSettings,
18061        window: &mut Window,
18062        cx: &mut Context<Self>,
18063    ) -> Entity<Self> {
18064        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18065
18066        let mut minimap = Editor::new_internal(
18067            EditorMode::Minimap {
18068                parent: cx.weak_entity(),
18069            },
18070            self.buffer.clone(),
18071            None,
18072            Some(self.display_map.clone()),
18073            window,
18074            cx,
18075        );
18076        minimap.scroll_manager.clone_state(&self.scroll_manager);
18077        minimap.set_text_style_refinement(TextStyleRefinement {
18078            font_size: Some(MINIMAP_FONT_SIZE),
18079            font_weight: Some(MINIMAP_FONT_WEIGHT),
18080            ..Default::default()
18081        });
18082        minimap.update_minimap_configuration(minimap_settings, cx);
18083        cx.new(|_| minimap)
18084    }
18085
18086    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18087        let current_line_highlight = minimap_settings
18088            .current_line_highlight
18089            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18090        self.set_current_line_highlight(Some(current_line_highlight));
18091    }
18092
18093    pub fn minimap(&self) -> Option<&Entity<Self>> {
18094        self.minimap
18095            .as_ref()
18096            .filter(|_| self.minimap_visibility.visible())
18097    }
18098
18099    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18100        let mut wrap_guides = smallvec![];
18101
18102        if self.show_wrap_guides == Some(false) {
18103            return wrap_guides;
18104        }
18105
18106        let settings = self.buffer.read(cx).language_settings(cx);
18107        if settings.show_wrap_guides {
18108            match self.soft_wrap_mode(cx) {
18109                SoftWrap::Column(soft_wrap) => {
18110                    wrap_guides.push((soft_wrap as usize, true));
18111                }
18112                SoftWrap::Bounded(soft_wrap) => {
18113                    wrap_guides.push((soft_wrap as usize, true));
18114                }
18115                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18116            }
18117            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18118        }
18119
18120        wrap_guides
18121    }
18122
18123    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18124        let settings = self.buffer.read(cx).language_settings(cx);
18125        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18126        match mode {
18127            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18128                SoftWrap::None
18129            }
18130            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18131            language_settings::SoftWrap::PreferredLineLength => {
18132                SoftWrap::Column(settings.preferred_line_length)
18133            }
18134            language_settings::SoftWrap::Bounded => {
18135                SoftWrap::Bounded(settings.preferred_line_length)
18136            }
18137        }
18138    }
18139
18140    pub fn set_soft_wrap_mode(
18141        &mut self,
18142        mode: language_settings::SoftWrap,
18143
18144        cx: &mut Context<Self>,
18145    ) {
18146        self.soft_wrap_mode_override = Some(mode);
18147        cx.notify();
18148    }
18149
18150    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18151        self.hard_wrap = hard_wrap;
18152        cx.notify();
18153    }
18154
18155    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18156        self.text_style_refinement = Some(style);
18157    }
18158
18159    /// called by the Element so we know what style we were most recently rendered with.
18160    pub(crate) fn set_style(
18161        &mut self,
18162        style: EditorStyle,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        // We intentionally do not inform the display map about the minimap style
18167        // so that wrapping is not recalculated and stays consistent for the editor
18168        // and its linked minimap.
18169        if !self.mode.is_minimap() {
18170            let rem_size = window.rem_size();
18171            self.display_map.update(cx, |map, cx| {
18172                map.set_font(
18173                    style.text.font(),
18174                    style.text.font_size.to_pixels(rem_size),
18175                    cx,
18176                )
18177            });
18178        }
18179        self.style = Some(style);
18180    }
18181
18182    pub fn style(&self) -> Option<&EditorStyle> {
18183        self.style.as_ref()
18184    }
18185
18186    // Called by the element. This method is not designed to be called outside of the editor
18187    // element's layout code because it does not notify when rewrapping is computed synchronously.
18188    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18189        self.display_map
18190            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18191    }
18192
18193    pub fn set_soft_wrap(&mut self) {
18194        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18195    }
18196
18197    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18198        if self.soft_wrap_mode_override.is_some() {
18199            self.soft_wrap_mode_override.take();
18200        } else {
18201            let soft_wrap = match self.soft_wrap_mode(cx) {
18202                SoftWrap::GitDiff => return,
18203                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18204                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18205                    language_settings::SoftWrap::None
18206                }
18207            };
18208            self.soft_wrap_mode_override = Some(soft_wrap);
18209        }
18210        cx.notify();
18211    }
18212
18213    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18214        let Some(workspace) = self.workspace() else {
18215            return;
18216        };
18217        let fs = workspace.read(cx).app_state().fs.clone();
18218        let current_show = TabBarSettings::get_global(cx).show;
18219        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18220            setting.show = Some(!current_show);
18221        });
18222    }
18223
18224    pub fn toggle_indent_guides(
18225        &mut self,
18226        _: &ToggleIndentGuides,
18227        _: &mut Window,
18228        cx: &mut Context<Self>,
18229    ) {
18230        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18231            self.buffer
18232                .read(cx)
18233                .language_settings(cx)
18234                .indent_guides
18235                .enabled
18236        });
18237        self.show_indent_guides = Some(!currently_enabled);
18238        cx.notify();
18239    }
18240
18241    fn should_show_indent_guides(&self) -> Option<bool> {
18242        self.show_indent_guides
18243    }
18244
18245    pub fn toggle_line_numbers(
18246        &mut self,
18247        _: &ToggleLineNumbers,
18248        _: &mut Window,
18249        cx: &mut Context<Self>,
18250    ) {
18251        let mut editor_settings = EditorSettings::get_global(cx).clone();
18252        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18253        EditorSettings::override_global(editor_settings, cx);
18254    }
18255
18256    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18257        if let Some(show_line_numbers) = self.show_line_numbers {
18258            return show_line_numbers;
18259        }
18260        EditorSettings::get_global(cx).gutter.line_numbers
18261    }
18262
18263    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18264        self.use_relative_line_numbers
18265            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18266    }
18267
18268    pub fn toggle_relative_line_numbers(
18269        &mut self,
18270        _: &ToggleRelativeLineNumbers,
18271        _: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        let is_relative = self.should_use_relative_line_numbers(cx);
18275        self.set_relative_line_number(Some(!is_relative), cx)
18276    }
18277
18278    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18279        self.use_relative_line_numbers = is_relative;
18280        cx.notify();
18281    }
18282
18283    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18284        self.show_gutter = show_gutter;
18285        cx.notify();
18286    }
18287
18288    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18289        self.show_scrollbars = ScrollbarAxes {
18290            horizontal: show,
18291            vertical: show,
18292        };
18293        cx.notify();
18294    }
18295
18296    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18297        self.show_scrollbars.vertical = show;
18298        cx.notify();
18299    }
18300
18301    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18302        self.show_scrollbars.horizontal = show;
18303        cx.notify();
18304    }
18305
18306    pub fn set_minimap_visibility(
18307        &mut self,
18308        minimap_visibility: MinimapVisibility,
18309        window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        if self.minimap_visibility != minimap_visibility {
18313            if minimap_visibility.visible() && self.minimap.is_none() {
18314                let minimap_settings = EditorSettings::get_global(cx).minimap;
18315                self.minimap =
18316                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18317            }
18318            self.minimap_visibility = minimap_visibility;
18319            cx.notify();
18320        }
18321    }
18322
18323    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18324        self.set_show_scrollbars(false, cx);
18325        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18326    }
18327
18328    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18329        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18330    }
18331
18332    /// Normally the text in full mode and auto height editors is padded on the
18333    /// left side by roughly half a character width for improved hit testing.
18334    ///
18335    /// Use this method to disable this for cases where this is not wanted (e.g.
18336    /// if you want to align the editor text with some other text above or below)
18337    /// or if you want to add this padding to single-line editors.
18338    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18339        self.offset_content = offset_content;
18340        cx.notify();
18341    }
18342
18343    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18344        self.show_line_numbers = Some(show_line_numbers);
18345        cx.notify();
18346    }
18347
18348    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18349        self.disable_expand_excerpt_buttons = true;
18350        cx.notify();
18351    }
18352
18353    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18354        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18355        cx.notify();
18356    }
18357
18358    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18359        self.show_code_actions = Some(show_code_actions);
18360        cx.notify();
18361    }
18362
18363    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18364        self.show_runnables = Some(show_runnables);
18365        cx.notify();
18366    }
18367
18368    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18369        self.show_breakpoints = Some(show_breakpoints);
18370        cx.notify();
18371    }
18372
18373    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18374        if self.display_map.read(cx).masked != masked {
18375            self.display_map.update(cx, |map, _| map.masked = masked);
18376        }
18377        cx.notify()
18378    }
18379
18380    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18381        self.show_wrap_guides = Some(show_wrap_guides);
18382        cx.notify();
18383    }
18384
18385    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18386        self.show_indent_guides = Some(show_indent_guides);
18387        cx.notify();
18388    }
18389
18390    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18391        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18392            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18393                if let Some(dir) = file.abs_path(cx).parent() {
18394                    return Some(dir.to_owned());
18395                }
18396            }
18397
18398            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18399                return Some(project_path.path.to_path_buf());
18400            }
18401        }
18402
18403        None
18404    }
18405
18406    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18407        self.active_excerpt(cx)?
18408            .1
18409            .read(cx)
18410            .file()
18411            .and_then(|f| f.as_local())
18412    }
18413
18414    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18415        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18416            let buffer = buffer.read(cx);
18417            if let Some(project_path) = buffer.project_path(cx) {
18418                let project = self.project.as_ref()?.read(cx);
18419                project.absolute_path(&project_path, cx)
18420            } else {
18421                buffer
18422                    .file()
18423                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18424            }
18425        })
18426    }
18427
18428    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18429        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18430            let project_path = buffer.read(cx).project_path(cx)?;
18431            let project = self.project.as_ref()?.read(cx);
18432            let entry = project.entry_for_path(&project_path, cx)?;
18433            let path = entry.path.to_path_buf();
18434            Some(path)
18435        })
18436    }
18437
18438    pub fn reveal_in_finder(
18439        &mut self,
18440        _: &RevealInFileManager,
18441        _window: &mut Window,
18442        cx: &mut Context<Self>,
18443    ) {
18444        if let Some(target) = self.target_file(cx) {
18445            cx.reveal_path(&target.abs_path(cx));
18446        }
18447    }
18448
18449    pub fn copy_path(
18450        &mut self,
18451        _: &zed_actions::workspace::CopyPath,
18452        _window: &mut Window,
18453        cx: &mut Context<Self>,
18454    ) {
18455        if let Some(path) = self.target_file_abs_path(cx) {
18456            if let Some(path) = path.to_str() {
18457                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18458            }
18459        }
18460    }
18461
18462    pub fn copy_relative_path(
18463        &mut self,
18464        _: &zed_actions::workspace::CopyRelativePath,
18465        _window: &mut Window,
18466        cx: &mut Context<Self>,
18467    ) {
18468        if let Some(path) = self.target_file_path(cx) {
18469            if let Some(path) = path.to_str() {
18470                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18471            }
18472        }
18473    }
18474
18475    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18476        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18477            buffer.read(cx).project_path(cx)
18478        } else {
18479            None
18480        }
18481    }
18482
18483    // Returns true if the editor handled a go-to-line request
18484    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18485        maybe!({
18486            let breakpoint_store = self.breakpoint_store.as_ref()?;
18487
18488            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18489            else {
18490                self.clear_row_highlights::<ActiveDebugLine>();
18491                return None;
18492            };
18493
18494            let position = active_stack_frame.position;
18495            let buffer_id = position.buffer_id?;
18496            let snapshot = self
18497                .project
18498                .as_ref()?
18499                .read(cx)
18500                .buffer_for_id(buffer_id, cx)?
18501                .read(cx)
18502                .snapshot();
18503
18504            let mut handled = false;
18505            for (id, ExcerptRange { context, .. }) in
18506                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18507            {
18508                if context.start.cmp(&position, &snapshot).is_ge()
18509                    || context.end.cmp(&position, &snapshot).is_lt()
18510                {
18511                    continue;
18512                }
18513                let snapshot = self.buffer.read(cx).snapshot(cx);
18514                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18515
18516                handled = true;
18517                self.clear_row_highlights::<ActiveDebugLine>();
18518
18519                self.go_to_line::<ActiveDebugLine>(
18520                    multibuffer_anchor,
18521                    Some(cx.theme().colors().editor_debugger_active_line_background),
18522                    window,
18523                    cx,
18524                );
18525
18526                cx.notify();
18527            }
18528
18529            handled.then_some(())
18530        })
18531        .is_some()
18532    }
18533
18534    pub fn copy_file_name_without_extension(
18535        &mut self,
18536        _: &CopyFileNameWithoutExtension,
18537        _: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        if let Some(file) = self.target_file(cx) {
18541            if let Some(file_stem) = file.path().file_stem() {
18542                if let Some(name) = file_stem.to_str() {
18543                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18544                }
18545            }
18546        }
18547    }
18548
18549    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18550        if let Some(file) = self.target_file(cx) {
18551            if let Some(file_name) = file.path().file_name() {
18552                if let Some(name) = file_name.to_str() {
18553                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18554                }
18555            }
18556        }
18557    }
18558
18559    pub fn toggle_git_blame(
18560        &mut self,
18561        _: &::git::Blame,
18562        window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18566
18567        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18568            self.start_git_blame(true, window, cx);
18569        }
18570
18571        cx.notify();
18572    }
18573
18574    pub fn toggle_git_blame_inline(
18575        &mut self,
18576        _: &ToggleGitBlameInline,
18577        window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) {
18580        self.toggle_git_blame_inline_internal(true, window, cx);
18581        cx.notify();
18582    }
18583
18584    pub fn open_git_blame_commit(
18585        &mut self,
18586        _: &OpenGitBlameCommit,
18587        window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) {
18590        self.open_git_blame_commit_internal(window, cx);
18591    }
18592
18593    fn open_git_blame_commit_internal(
18594        &mut self,
18595        window: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) -> Option<()> {
18598        let blame = self.blame.as_ref()?;
18599        let snapshot = self.snapshot(window, cx);
18600        let cursor = self.selections.newest::<Point>(cx).head();
18601        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18602        let blame_entry = blame
18603            .update(cx, |blame, cx| {
18604                blame
18605                    .blame_for_rows(
18606                        &[RowInfo {
18607                            buffer_id: Some(buffer.remote_id()),
18608                            buffer_row: Some(point.row),
18609                            ..Default::default()
18610                        }],
18611                        cx,
18612                    )
18613                    .next()
18614            })
18615            .flatten()?;
18616        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18617        let repo = blame.read(cx).repository(cx)?;
18618        let workspace = self.workspace()?.downgrade();
18619        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18620        None
18621    }
18622
18623    pub fn git_blame_inline_enabled(&self) -> bool {
18624        self.git_blame_inline_enabled
18625    }
18626
18627    pub fn toggle_selection_menu(
18628        &mut self,
18629        _: &ToggleSelectionMenu,
18630        _: &mut Window,
18631        cx: &mut Context<Self>,
18632    ) {
18633        self.show_selection_menu = self
18634            .show_selection_menu
18635            .map(|show_selections_menu| !show_selections_menu)
18636            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18637
18638        cx.notify();
18639    }
18640
18641    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18642        self.show_selection_menu
18643            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18644    }
18645
18646    fn start_git_blame(
18647        &mut self,
18648        user_triggered: bool,
18649        window: &mut Window,
18650        cx: &mut Context<Self>,
18651    ) {
18652        if let Some(project) = self.project.as_ref() {
18653            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18654                return;
18655            };
18656
18657            if buffer.read(cx).file().is_none() {
18658                return;
18659            }
18660
18661            let focused = self.focus_handle(cx).contains_focused(window, cx);
18662
18663            let project = project.clone();
18664            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18665            self.blame_subscription =
18666                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18667            self.blame = Some(blame);
18668        }
18669    }
18670
18671    fn toggle_git_blame_inline_internal(
18672        &mut self,
18673        user_triggered: bool,
18674        window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        if self.git_blame_inline_enabled {
18678            self.git_blame_inline_enabled = false;
18679            self.show_git_blame_inline = false;
18680            self.show_git_blame_inline_delay_task.take();
18681        } else {
18682            self.git_blame_inline_enabled = true;
18683            self.start_git_blame_inline(user_triggered, window, cx);
18684        }
18685
18686        cx.notify();
18687    }
18688
18689    fn start_git_blame_inline(
18690        &mut self,
18691        user_triggered: bool,
18692        window: &mut Window,
18693        cx: &mut Context<Self>,
18694    ) {
18695        self.start_git_blame(user_triggered, window, cx);
18696
18697        if ProjectSettings::get_global(cx)
18698            .git
18699            .inline_blame_delay()
18700            .is_some()
18701        {
18702            self.start_inline_blame_timer(window, cx);
18703        } else {
18704            self.show_git_blame_inline = true
18705        }
18706    }
18707
18708    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18709        self.blame.as_ref()
18710    }
18711
18712    pub fn show_git_blame_gutter(&self) -> bool {
18713        self.show_git_blame_gutter
18714    }
18715
18716    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18717        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18718    }
18719
18720    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18721        self.show_git_blame_inline
18722            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18723            && !self.newest_selection_head_on_empty_line(cx)
18724            && self.has_blame_entries(cx)
18725    }
18726
18727    fn has_blame_entries(&self, cx: &App) -> bool {
18728        self.blame()
18729            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18730    }
18731
18732    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18733        let cursor_anchor = self.selections.newest_anchor().head();
18734
18735        let snapshot = self.buffer.read(cx).snapshot(cx);
18736        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18737
18738        snapshot.line_len(buffer_row) == 0
18739    }
18740
18741    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18742        let buffer_and_selection = maybe!({
18743            let selection = self.selections.newest::<Point>(cx);
18744            let selection_range = selection.range();
18745
18746            let multi_buffer = self.buffer().read(cx);
18747            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18748            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18749
18750            let (buffer, range, _) = if selection.reversed {
18751                buffer_ranges.first()
18752            } else {
18753                buffer_ranges.last()
18754            }?;
18755
18756            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18757                ..text::ToPoint::to_point(&range.end, &buffer).row;
18758            Some((
18759                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18760                selection,
18761            ))
18762        });
18763
18764        let Some((buffer, selection)) = buffer_and_selection else {
18765            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18766        };
18767
18768        let Some(project) = self.project.as_ref() else {
18769            return Task::ready(Err(anyhow!("editor does not have project")));
18770        };
18771
18772        project.update(cx, |project, cx| {
18773            project.get_permalink_to_line(&buffer, selection, cx)
18774        })
18775    }
18776
18777    pub fn copy_permalink_to_line(
18778        &mut self,
18779        _: &CopyPermalinkToLine,
18780        window: &mut Window,
18781        cx: &mut Context<Self>,
18782    ) {
18783        let permalink_task = self.get_permalink_to_line(cx);
18784        let workspace = self.workspace();
18785
18786        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18787            Ok(permalink) => {
18788                cx.update(|_, cx| {
18789                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18790                })
18791                .ok();
18792            }
18793            Err(err) => {
18794                let message = format!("Failed to copy permalink: {err}");
18795
18796                anyhow::Result::<()>::Err(err).log_err();
18797
18798                if let Some(workspace) = workspace {
18799                    workspace
18800                        .update_in(cx, |workspace, _, cx| {
18801                            struct CopyPermalinkToLine;
18802
18803                            workspace.show_toast(
18804                                Toast::new(
18805                                    NotificationId::unique::<CopyPermalinkToLine>(),
18806                                    message,
18807                                ),
18808                                cx,
18809                            )
18810                        })
18811                        .ok();
18812                }
18813            }
18814        })
18815        .detach();
18816    }
18817
18818    pub fn copy_file_location(
18819        &mut self,
18820        _: &CopyFileLocation,
18821        _: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) {
18824        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18825        if let Some(file) = self.target_file(cx) {
18826            if let Some(path) = file.path().to_str() {
18827                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18828            }
18829        }
18830    }
18831
18832    pub fn open_permalink_to_line(
18833        &mut self,
18834        _: &OpenPermalinkToLine,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        let permalink_task = self.get_permalink_to_line(cx);
18839        let workspace = self.workspace();
18840
18841        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18842            Ok(permalink) => {
18843                cx.update(|_, cx| {
18844                    cx.open_url(permalink.as_ref());
18845                })
18846                .ok();
18847            }
18848            Err(err) => {
18849                let message = format!("Failed to open permalink: {err}");
18850
18851                anyhow::Result::<()>::Err(err).log_err();
18852
18853                if let Some(workspace) = workspace {
18854                    workspace
18855                        .update(cx, |workspace, cx| {
18856                            struct OpenPermalinkToLine;
18857
18858                            workspace.show_toast(
18859                                Toast::new(
18860                                    NotificationId::unique::<OpenPermalinkToLine>(),
18861                                    message,
18862                                ),
18863                                cx,
18864                            )
18865                        })
18866                        .ok();
18867                }
18868            }
18869        })
18870        .detach();
18871    }
18872
18873    pub fn insert_uuid_v4(
18874        &mut self,
18875        _: &InsertUuidV4,
18876        window: &mut Window,
18877        cx: &mut Context<Self>,
18878    ) {
18879        self.insert_uuid(UuidVersion::V4, window, cx);
18880    }
18881
18882    pub fn insert_uuid_v7(
18883        &mut self,
18884        _: &InsertUuidV7,
18885        window: &mut Window,
18886        cx: &mut Context<Self>,
18887    ) {
18888        self.insert_uuid(UuidVersion::V7, window, cx);
18889    }
18890
18891    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18893        self.transact(window, cx, |this, window, cx| {
18894            let edits = this
18895                .selections
18896                .all::<Point>(cx)
18897                .into_iter()
18898                .map(|selection| {
18899                    let uuid = match version {
18900                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18901                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18902                    };
18903
18904                    (selection.range(), uuid.to_string())
18905                });
18906            this.edit(edits, cx);
18907            this.refresh_inline_completion(true, false, window, cx);
18908        });
18909    }
18910
18911    pub fn open_selections_in_multibuffer(
18912        &mut self,
18913        _: &OpenSelectionsInMultibuffer,
18914        window: &mut Window,
18915        cx: &mut Context<Self>,
18916    ) {
18917        let multibuffer = self.buffer.read(cx);
18918
18919        let Some(buffer) = multibuffer.as_singleton() else {
18920            return;
18921        };
18922
18923        let Some(workspace) = self.workspace() else {
18924            return;
18925        };
18926
18927        let title = multibuffer.title(cx).to_string();
18928
18929        let locations = self
18930            .selections
18931            .all_anchors(cx)
18932            .into_iter()
18933            .map(|selection| Location {
18934                buffer: buffer.clone(),
18935                range: selection.start.text_anchor..selection.end.text_anchor,
18936            })
18937            .collect::<Vec<_>>();
18938
18939        cx.spawn_in(window, async move |_, cx| {
18940            workspace.update_in(cx, |workspace, window, cx| {
18941                Self::open_locations_in_multibuffer(
18942                    workspace,
18943                    locations,
18944                    format!("Selections for '{title}'"),
18945                    false,
18946                    MultibufferSelectionMode::All,
18947                    window,
18948                    cx,
18949                );
18950            })
18951        })
18952        .detach();
18953    }
18954
18955    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18956    /// last highlight added will be used.
18957    ///
18958    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18959    pub fn highlight_rows<T: 'static>(
18960        &mut self,
18961        range: Range<Anchor>,
18962        color: Hsla,
18963        options: RowHighlightOptions,
18964        cx: &mut Context<Self>,
18965    ) {
18966        let snapshot = self.buffer().read(cx).snapshot(cx);
18967        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18968        let ix = row_highlights.binary_search_by(|highlight| {
18969            Ordering::Equal
18970                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18971                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18972        });
18973
18974        if let Err(mut ix) = ix {
18975            let index = post_inc(&mut self.highlight_order);
18976
18977            // If this range intersects with the preceding highlight, then merge it with
18978            // the preceding highlight. Otherwise insert a new highlight.
18979            let mut merged = false;
18980            if ix > 0 {
18981                let prev_highlight = &mut row_highlights[ix - 1];
18982                if prev_highlight
18983                    .range
18984                    .end
18985                    .cmp(&range.start, &snapshot)
18986                    .is_ge()
18987                {
18988                    ix -= 1;
18989                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18990                        prev_highlight.range.end = range.end;
18991                    }
18992                    merged = true;
18993                    prev_highlight.index = index;
18994                    prev_highlight.color = color;
18995                    prev_highlight.options = options;
18996                }
18997            }
18998
18999            if !merged {
19000                row_highlights.insert(
19001                    ix,
19002                    RowHighlight {
19003                        range: range.clone(),
19004                        index,
19005                        color,
19006                        options,
19007                        type_id: TypeId::of::<T>(),
19008                    },
19009                );
19010            }
19011
19012            // If any of the following highlights intersect with this one, merge them.
19013            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19014                let highlight = &row_highlights[ix];
19015                if next_highlight
19016                    .range
19017                    .start
19018                    .cmp(&highlight.range.end, &snapshot)
19019                    .is_le()
19020                {
19021                    if next_highlight
19022                        .range
19023                        .end
19024                        .cmp(&highlight.range.end, &snapshot)
19025                        .is_gt()
19026                    {
19027                        row_highlights[ix].range.end = next_highlight.range.end;
19028                    }
19029                    row_highlights.remove(ix + 1);
19030                } else {
19031                    break;
19032                }
19033            }
19034        }
19035    }
19036
19037    /// Remove any highlighted row ranges of the given type that intersect the
19038    /// given ranges.
19039    pub fn remove_highlighted_rows<T: 'static>(
19040        &mut self,
19041        ranges_to_remove: Vec<Range<Anchor>>,
19042        cx: &mut Context<Self>,
19043    ) {
19044        let snapshot = self.buffer().read(cx).snapshot(cx);
19045        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19046        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19047        row_highlights.retain(|highlight| {
19048            while let Some(range_to_remove) = ranges_to_remove.peek() {
19049                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19050                    Ordering::Less | Ordering::Equal => {
19051                        ranges_to_remove.next();
19052                    }
19053                    Ordering::Greater => {
19054                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19055                            Ordering::Less | Ordering::Equal => {
19056                                return false;
19057                            }
19058                            Ordering::Greater => break,
19059                        }
19060                    }
19061                }
19062            }
19063
19064            true
19065        })
19066    }
19067
19068    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19069    pub fn clear_row_highlights<T: 'static>(&mut self) {
19070        self.highlighted_rows.remove(&TypeId::of::<T>());
19071    }
19072
19073    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19074    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19075        self.highlighted_rows
19076            .get(&TypeId::of::<T>())
19077            .map_or(&[] as &[_], |vec| vec.as_slice())
19078            .iter()
19079            .map(|highlight| (highlight.range.clone(), highlight.color))
19080    }
19081
19082    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19083    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19084    /// Allows to ignore certain kinds of highlights.
19085    pub fn highlighted_display_rows(
19086        &self,
19087        window: &mut Window,
19088        cx: &mut App,
19089    ) -> BTreeMap<DisplayRow, LineHighlight> {
19090        let snapshot = self.snapshot(window, cx);
19091        let mut used_highlight_orders = HashMap::default();
19092        self.highlighted_rows
19093            .iter()
19094            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19095            .fold(
19096                BTreeMap::<DisplayRow, LineHighlight>::new(),
19097                |mut unique_rows, highlight| {
19098                    let start = highlight.range.start.to_display_point(&snapshot);
19099                    let end = highlight.range.end.to_display_point(&snapshot);
19100                    let start_row = start.row().0;
19101                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19102                        && end.column() == 0
19103                    {
19104                        end.row().0.saturating_sub(1)
19105                    } else {
19106                        end.row().0
19107                    };
19108                    for row in start_row..=end_row {
19109                        let used_index =
19110                            used_highlight_orders.entry(row).or_insert(highlight.index);
19111                        if highlight.index >= *used_index {
19112                            *used_index = highlight.index;
19113                            unique_rows.insert(
19114                                DisplayRow(row),
19115                                LineHighlight {
19116                                    include_gutter: highlight.options.include_gutter,
19117                                    border: None,
19118                                    background: highlight.color.into(),
19119                                    type_id: Some(highlight.type_id),
19120                                },
19121                            );
19122                        }
19123                    }
19124                    unique_rows
19125                },
19126            )
19127    }
19128
19129    pub fn highlighted_display_row_for_autoscroll(
19130        &self,
19131        snapshot: &DisplaySnapshot,
19132    ) -> Option<DisplayRow> {
19133        self.highlighted_rows
19134            .values()
19135            .flat_map(|highlighted_rows| highlighted_rows.iter())
19136            .filter_map(|highlight| {
19137                if highlight.options.autoscroll {
19138                    Some(highlight.range.start.to_display_point(snapshot).row())
19139                } else {
19140                    None
19141                }
19142            })
19143            .min()
19144    }
19145
19146    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19147        self.highlight_background::<SearchWithinRange>(
19148            ranges,
19149            |colors| colors.colors().editor_document_highlight_read_background,
19150            cx,
19151        )
19152    }
19153
19154    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19155        self.breadcrumb_header = Some(new_header);
19156    }
19157
19158    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19159        self.clear_background_highlights::<SearchWithinRange>(cx);
19160    }
19161
19162    pub fn highlight_background<T: 'static>(
19163        &mut self,
19164        ranges: &[Range<Anchor>],
19165        color_fetcher: fn(&Theme) -> Hsla,
19166        cx: &mut Context<Self>,
19167    ) {
19168        self.background_highlights.insert(
19169            HighlightKey::Type(TypeId::of::<T>()),
19170            (color_fetcher, Arc::from(ranges)),
19171        );
19172        self.scrollbar_marker_state.dirty = true;
19173        cx.notify();
19174    }
19175
19176    pub fn highlight_background_key<T: 'static>(
19177        &mut self,
19178        key: usize,
19179        ranges: &[Range<Anchor>],
19180        color_fetcher: fn(&Theme) -> Hsla,
19181        cx: &mut Context<Self>,
19182    ) {
19183        self.background_highlights.insert(
19184            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19185            (color_fetcher, Arc::from(ranges)),
19186        );
19187        self.scrollbar_marker_state.dirty = true;
19188        cx.notify();
19189    }
19190
19191    pub fn clear_background_highlights<T: 'static>(
19192        &mut self,
19193        cx: &mut Context<Self>,
19194    ) -> Option<BackgroundHighlight> {
19195        let text_highlights = self
19196            .background_highlights
19197            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19198        if !text_highlights.1.is_empty() {
19199            self.scrollbar_marker_state.dirty = true;
19200            cx.notify();
19201        }
19202        Some(text_highlights)
19203    }
19204
19205    pub fn highlight_gutter<T: 'static>(
19206        &mut self,
19207        ranges: impl Into<Vec<Range<Anchor>>>,
19208        color_fetcher: fn(&App) -> Hsla,
19209        cx: &mut Context<Self>,
19210    ) {
19211        self.gutter_highlights
19212            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19213        cx.notify();
19214    }
19215
19216    pub fn clear_gutter_highlights<T: 'static>(
19217        &mut self,
19218        cx: &mut Context<Self>,
19219    ) -> Option<GutterHighlight> {
19220        cx.notify();
19221        self.gutter_highlights.remove(&TypeId::of::<T>())
19222    }
19223
19224    pub fn insert_gutter_highlight<T: 'static>(
19225        &mut self,
19226        range: Range<Anchor>,
19227        color_fetcher: fn(&App) -> Hsla,
19228        cx: &mut Context<Self>,
19229    ) {
19230        let snapshot = self.buffer().read(cx).snapshot(cx);
19231        let mut highlights = self
19232            .gutter_highlights
19233            .remove(&TypeId::of::<T>())
19234            .map(|(_, highlights)| highlights)
19235            .unwrap_or_default();
19236        let ix = highlights.binary_search_by(|highlight| {
19237            Ordering::Equal
19238                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19239                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19240        });
19241        if let Err(ix) = ix {
19242            highlights.insert(ix, range);
19243        }
19244        self.gutter_highlights
19245            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19246    }
19247
19248    pub fn remove_gutter_highlights<T: 'static>(
19249        &mut self,
19250        ranges_to_remove: Vec<Range<Anchor>>,
19251        cx: &mut Context<Self>,
19252    ) {
19253        let snapshot = self.buffer().read(cx).snapshot(cx);
19254        let Some((color_fetcher, mut gutter_highlights)) =
19255            self.gutter_highlights.remove(&TypeId::of::<T>())
19256        else {
19257            return;
19258        };
19259        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19260        gutter_highlights.retain(|highlight| {
19261            while let Some(range_to_remove) = ranges_to_remove.peek() {
19262                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19263                    Ordering::Less | Ordering::Equal => {
19264                        ranges_to_remove.next();
19265                    }
19266                    Ordering::Greater => {
19267                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19268                            Ordering::Less | Ordering::Equal => {
19269                                return false;
19270                            }
19271                            Ordering::Greater => break,
19272                        }
19273                    }
19274                }
19275            }
19276
19277            true
19278        });
19279        self.gutter_highlights
19280            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19281    }
19282
19283    #[cfg(feature = "test-support")]
19284    pub fn all_text_highlights(
19285        &self,
19286        window: &mut Window,
19287        cx: &mut Context<Self>,
19288    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19289        let snapshot = self.snapshot(window, cx);
19290        self.display_map.update(cx, |display_map, _| {
19291            display_map
19292                .all_text_highlights()
19293                .map(|highlight| {
19294                    let (style, ranges) = highlight.as_ref();
19295                    (
19296                        *style,
19297                        ranges
19298                            .iter()
19299                            .map(|range| range.clone().to_display_points(&snapshot))
19300                            .collect(),
19301                    )
19302                })
19303                .collect()
19304        })
19305    }
19306
19307    #[cfg(feature = "test-support")]
19308    pub fn all_text_background_highlights(
19309        &self,
19310        window: &mut Window,
19311        cx: &mut Context<Self>,
19312    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19313        let snapshot = self.snapshot(window, cx);
19314        let buffer = &snapshot.buffer_snapshot;
19315        let start = buffer.anchor_before(0);
19316        let end = buffer.anchor_after(buffer.len());
19317        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19318    }
19319
19320    #[cfg(feature = "test-support")]
19321    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19322        let snapshot = self.buffer().read(cx).snapshot(cx);
19323
19324        let highlights = self
19325            .background_highlights
19326            .get(&HighlightKey::Type(TypeId::of::<
19327                items::BufferSearchHighlights,
19328            >()));
19329
19330        if let Some((_color, ranges)) = highlights {
19331            ranges
19332                .iter()
19333                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19334                .collect_vec()
19335        } else {
19336            vec![]
19337        }
19338    }
19339
19340    fn document_highlights_for_position<'a>(
19341        &'a self,
19342        position: Anchor,
19343        buffer: &'a MultiBufferSnapshot,
19344    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19345        let read_highlights = self
19346            .background_highlights
19347            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19348            .map(|h| &h.1);
19349        let write_highlights = self
19350            .background_highlights
19351            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19352            .map(|h| &h.1);
19353        let left_position = position.bias_left(buffer);
19354        let right_position = position.bias_right(buffer);
19355        read_highlights
19356            .into_iter()
19357            .chain(write_highlights)
19358            .flat_map(move |ranges| {
19359                let start_ix = match ranges.binary_search_by(|probe| {
19360                    let cmp = probe.end.cmp(&left_position, buffer);
19361                    if cmp.is_ge() {
19362                        Ordering::Greater
19363                    } else {
19364                        Ordering::Less
19365                    }
19366                }) {
19367                    Ok(i) | Err(i) => i,
19368                };
19369
19370                ranges[start_ix..]
19371                    .iter()
19372                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19373            })
19374    }
19375
19376    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19377        self.background_highlights
19378            .get(&HighlightKey::Type(TypeId::of::<T>()))
19379            .map_or(false, |(_, highlights)| !highlights.is_empty())
19380    }
19381
19382    pub fn background_highlights_in_range(
19383        &self,
19384        search_range: Range<Anchor>,
19385        display_snapshot: &DisplaySnapshot,
19386        theme: &Theme,
19387    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19388        let mut results = Vec::new();
19389        for (color_fetcher, ranges) in self.background_highlights.values() {
19390            let color = color_fetcher(theme);
19391            let start_ix = match ranges.binary_search_by(|probe| {
19392                let cmp = probe
19393                    .end
19394                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19395                if cmp.is_gt() {
19396                    Ordering::Greater
19397                } else {
19398                    Ordering::Less
19399                }
19400            }) {
19401                Ok(i) | Err(i) => i,
19402            };
19403            for range in &ranges[start_ix..] {
19404                if range
19405                    .start
19406                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19407                    .is_ge()
19408                {
19409                    break;
19410                }
19411
19412                let start = range.start.to_display_point(display_snapshot);
19413                let end = range.end.to_display_point(display_snapshot);
19414                results.push((start..end, color))
19415            }
19416        }
19417        results
19418    }
19419
19420    pub fn background_highlight_row_ranges<T: 'static>(
19421        &self,
19422        search_range: Range<Anchor>,
19423        display_snapshot: &DisplaySnapshot,
19424        count: usize,
19425    ) -> Vec<RangeInclusive<DisplayPoint>> {
19426        let mut results = Vec::new();
19427        let Some((_, ranges)) = self
19428            .background_highlights
19429            .get(&HighlightKey::Type(TypeId::of::<T>()))
19430        else {
19431            return vec![];
19432        };
19433
19434        let start_ix = match ranges.binary_search_by(|probe| {
19435            let cmp = probe
19436                .end
19437                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19438            if cmp.is_gt() {
19439                Ordering::Greater
19440            } else {
19441                Ordering::Less
19442            }
19443        }) {
19444            Ok(i) | Err(i) => i,
19445        };
19446        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19447            if let (Some(start_display), Some(end_display)) = (start, end) {
19448                results.push(
19449                    start_display.to_display_point(display_snapshot)
19450                        ..=end_display.to_display_point(display_snapshot),
19451                );
19452            }
19453        };
19454        let mut start_row: Option<Point> = None;
19455        let mut end_row: Option<Point> = None;
19456        if ranges.len() > count {
19457            return Vec::new();
19458        }
19459        for range in &ranges[start_ix..] {
19460            if range
19461                .start
19462                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19463                .is_ge()
19464            {
19465                break;
19466            }
19467            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19468            if let Some(current_row) = &end_row {
19469                if end.row == current_row.row {
19470                    continue;
19471                }
19472            }
19473            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19474            if start_row.is_none() {
19475                assert_eq!(end_row, None);
19476                start_row = Some(start);
19477                end_row = Some(end);
19478                continue;
19479            }
19480            if let Some(current_end) = end_row.as_mut() {
19481                if start.row > current_end.row + 1 {
19482                    push_region(start_row, end_row);
19483                    start_row = Some(start);
19484                    end_row = Some(end);
19485                } else {
19486                    // Merge two hunks.
19487                    *current_end = end;
19488                }
19489            } else {
19490                unreachable!();
19491            }
19492        }
19493        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19494        push_region(start_row, end_row);
19495        results
19496    }
19497
19498    pub fn gutter_highlights_in_range(
19499        &self,
19500        search_range: Range<Anchor>,
19501        display_snapshot: &DisplaySnapshot,
19502        cx: &App,
19503    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19504        let mut results = Vec::new();
19505        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19506            let color = color_fetcher(cx);
19507            let start_ix = match ranges.binary_search_by(|probe| {
19508                let cmp = probe
19509                    .end
19510                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19511                if cmp.is_gt() {
19512                    Ordering::Greater
19513                } else {
19514                    Ordering::Less
19515                }
19516            }) {
19517                Ok(i) | Err(i) => i,
19518            };
19519            for range in &ranges[start_ix..] {
19520                if range
19521                    .start
19522                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19523                    .is_ge()
19524                {
19525                    break;
19526                }
19527
19528                let start = range.start.to_display_point(display_snapshot);
19529                let end = range.end.to_display_point(display_snapshot);
19530                results.push((start..end, color))
19531            }
19532        }
19533        results
19534    }
19535
19536    /// Get the text ranges corresponding to the redaction query
19537    pub fn redacted_ranges(
19538        &self,
19539        search_range: Range<Anchor>,
19540        display_snapshot: &DisplaySnapshot,
19541        cx: &App,
19542    ) -> Vec<Range<DisplayPoint>> {
19543        display_snapshot
19544            .buffer_snapshot
19545            .redacted_ranges(search_range, |file| {
19546                if let Some(file) = file {
19547                    file.is_private()
19548                        && EditorSettings::get(
19549                            Some(SettingsLocation {
19550                                worktree_id: file.worktree_id(cx),
19551                                path: file.path().as_ref(),
19552                            }),
19553                            cx,
19554                        )
19555                        .redact_private_values
19556                } else {
19557                    false
19558                }
19559            })
19560            .map(|range| {
19561                range.start.to_display_point(display_snapshot)
19562                    ..range.end.to_display_point(display_snapshot)
19563            })
19564            .collect()
19565    }
19566
19567    pub fn highlight_text_key<T: 'static>(
19568        &mut self,
19569        key: usize,
19570        ranges: Vec<Range<Anchor>>,
19571        style: HighlightStyle,
19572        cx: &mut Context<Self>,
19573    ) {
19574        self.display_map.update(cx, |map, _| {
19575            map.highlight_text(
19576                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19577                ranges,
19578                style,
19579            );
19580        });
19581        cx.notify();
19582    }
19583
19584    pub fn highlight_text<T: 'static>(
19585        &mut self,
19586        ranges: Vec<Range<Anchor>>,
19587        style: HighlightStyle,
19588        cx: &mut Context<Self>,
19589    ) {
19590        self.display_map.update(cx, |map, _| {
19591            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19592        });
19593        cx.notify();
19594    }
19595
19596    pub(crate) fn highlight_inlays<T: 'static>(
19597        &mut self,
19598        highlights: Vec<InlayHighlight>,
19599        style: HighlightStyle,
19600        cx: &mut Context<Self>,
19601    ) {
19602        self.display_map.update(cx, |map, _| {
19603            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19604        });
19605        cx.notify();
19606    }
19607
19608    pub fn text_highlights<'a, T: 'static>(
19609        &'a self,
19610        cx: &'a App,
19611    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19612        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19613    }
19614
19615    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19616        let cleared = self
19617            .display_map
19618            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19619        if cleared {
19620            cx.notify();
19621        }
19622    }
19623
19624    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19625        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19626            && self.focus_handle.is_focused(window)
19627    }
19628
19629    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19630        self.show_cursor_when_unfocused = is_enabled;
19631        cx.notify();
19632    }
19633
19634    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19635        cx.notify();
19636    }
19637
19638    fn on_debug_session_event(
19639        &mut self,
19640        _session: Entity<Session>,
19641        event: &SessionEvent,
19642        cx: &mut Context<Self>,
19643    ) {
19644        match event {
19645            SessionEvent::InvalidateInlineValue => {
19646                self.refresh_inline_values(cx);
19647            }
19648            _ => {}
19649        }
19650    }
19651
19652    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19653        let Some(project) = self.project.clone() else {
19654            return;
19655        };
19656
19657        if !self.inline_value_cache.enabled {
19658            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19659            self.splice_inlays(&inlays, Vec::new(), cx);
19660            return;
19661        }
19662
19663        let current_execution_position = self
19664            .highlighted_rows
19665            .get(&TypeId::of::<ActiveDebugLine>())
19666            .and_then(|lines| lines.last().map(|line| line.range.end));
19667
19668        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19669            let inline_values = editor
19670                .update(cx, |editor, cx| {
19671                    let Some(current_execution_position) = current_execution_position else {
19672                        return Some(Task::ready(Ok(Vec::new())));
19673                    };
19674
19675                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19676                        let snapshot = buffer.snapshot(cx);
19677
19678                        let excerpt = snapshot.excerpt_containing(
19679                            current_execution_position..current_execution_position,
19680                        )?;
19681
19682                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19683                    })?;
19684
19685                    let range =
19686                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19687
19688                    project.inline_values(buffer, range, cx)
19689                })
19690                .ok()
19691                .flatten()?
19692                .await
19693                .context("refreshing debugger inlays")
19694                .log_err()?;
19695
19696            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19697
19698            for (buffer_id, inline_value) in inline_values
19699                .into_iter()
19700                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19701            {
19702                buffer_inline_values
19703                    .entry(buffer_id)
19704                    .or_default()
19705                    .push(inline_value);
19706            }
19707
19708            editor
19709                .update(cx, |editor, cx| {
19710                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19711                    let mut new_inlays = Vec::default();
19712
19713                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19714                        let buffer_id = buffer_snapshot.remote_id();
19715                        buffer_inline_values
19716                            .get(&buffer_id)
19717                            .into_iter()
19718                            .flatten()
19719                            .for_each(|hint| {
19720                                let inlay = Inlay::debugger(
19721                                    post_inc(&mut editor.next_inlay_id),
19722                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19723                                    hint.text(),
19724                                );
19725                                if !inlay.text.chars().contains(&'\n') {
19726                                    new_inlays.push(inlay);
19727                                }
19728                            });
19729                    }
19730
19731                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19732                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19733
19734                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19735                })
19736                .ok()?;
19737            Some(())
19738        });
19739    }
19740
19741    fn on_buffer_event(
19742        &mut self,
19743        multibuffer: &Entity<MultiBuffer>,
19744        event: &multi_buffer::Event,
19745        window: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        match event {
19749            multi_buffer::Event::Edited {
19750                singleton_buffer_edited,
19751                edited_buffer,
19752            } => {
19753                self.scrollbar_marker_state.dirty = true;
19754                self.active_indent_guides_state.dirty = true;
19755                self.refresh_active_diagnostics(cx);
19756                self.refresh_code_actions(window, cx);
19757                self.refresh_selected_text_highlights(true, window, cx);
19758                self.refresh_single_line_folds(window, cx);
19759                refresh_matching_bracket_highlights(self, window, cx);
19760                if self.has_active_inline_completion() {
19761                    self.update_visible_inline_completion(window, cx);
19762                }
19763                if let Some(project) = self.project.as_ref() {
19764                    if let Some(edited_buffer) = edited_buffer {
19765                        project.update(cx, |project, cx| {
19766                            self.registered_buffers
19767                                .entry(edited_buffer.read(cx).remote_id())
19768                                .or_insert_with(|| {
19769                                    project
19770                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19771                                });
19772                        });
19773                    }
19774                }
19775                cx.emit(EditorEvent::BufferEdited);
19776                cx.emit(SearchEvent::MatchesInvalidated);
19777
19778                if let Some(buffer) = edited_buffer {
19779                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19780                }
19781
19782                if *singleton_buffer_edited {
19783                    if let Some(buffer) = edited_buffer {
19784                        if buffer.read(cx).file().is_none() {
19785                            cx.emit(EditorEvent::TitleChanged);
19786                        }
19787                    }
19788                    if let Some(project) = &self.project {
19789                        #[allow(clippy::mutable_key_type)]
19790                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19791                            multibuffer
19792                                .all_buffers()
19793                                .into_iter()
19794                                .filter_map(|buffer| {
19795                                    buffer.update(cx, |buffer, cx| {
19796                                        let language = buffer.language()?;
19797                                        let should_discard = project.update(cx, |project, cx| {
19798                                            project.is_local()
19799                                                && !project.has_language_servers_for(buffer, cx)
19800                                        });
19801                                        should_discard.not().then_some(language.clone())
19802                                    })
19803                                })
19804                                .collect::<HashSet<_>>()
19805                        });
19806                        if !languages_affected.is_empty() {
19807                            self.refresh_inlay_hints(
19808                                InlayHintRefreshReason::BufferEdited(languages_affected),
19809                                cx,
19810                            );
19811                        }
19812                    }
19813                }
19814
19815                let Some(project) = &self.project else { return };
19816                let (telemetry, is_via_ssh) = {
19817                    let project = project.read(cx);
19818                    let telemetry = project.client().telemetry().clone();
19819                    let is_via_ssh = project.is_via_ssh();
19820                    (telemetry, is_via_ssh)
19821                };
19822                refresh_linked_ranges(self, window, cx);
19823                telemetry.log_edit_event("editor", is_via_ssh);
19824            }
19825            multi_buffer::Event::ExcerptsAdded {
19826                buffer,
19827                predecessor,
19828                excerpts,
19829            } => {
19830                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19831                let buffer_id = buffer.read(cx).remote_id();
19832                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19833                    if let Some(project) = &self.project {
19834                        update_uncommitted_diff_for_buffer(
19835                            cx.entity(),
19836                            project,
19837                            [buffer.clone()],
19838                            self.buffer.clone(),
19839                            cx,
19840                        )
19841                        .detach();
19842                    }
19843                }
19844                self.update_lsp_data(false, Some(buffer_id), window, cx);
19845                cx.emit(EditorEvent::ExcerptsAdded {
19846                    buffer: buffer.clone(),
19847                    predecessor: *predecessor,
19848                    excerpts: excerpts.clone(),
19849                });
19850                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19851            }
19852            multi_buffer::Event::ExcerptsRemoved {
19853                ids,
19854                removed_buffer_ids,
19855            } => {
19856                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19857                let buffer = self.buffer.read(cx);
19858                self.registered_buffers
19859                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19860                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19861                cx.emit(EditorEvent::ExcerptsRemoved {
19862                    ids: ids.clone(),
19863                    removed_buffer_ids: removed_buffer_ids.clone(),
19864                });
19865            }
19866            multi_buffer::Event::ExcerptsEdited {
19867                excerpt_ids,
19868                buffer_ids,
19869            } => {
19870                self.display_map.update(cx, |map, cx| {
19871                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19872                });
19873                cx.emit(EditorEvent::ExcerptsEdited {
19874                    ids: excerpt_ids.clone(),
19875                });
19876            }
19877            multi_buffer::Event::ExcerptsExpanded { ids } => {
19878                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19879                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19880            }
19881            multi_buffer::Event::Reparsed(buffer_id) => {
19882                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19883                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19884
19885                cx.emit(EditorEvent::Reparsed(*buffer_id));
19886            }
19887            multi_buffer::Event::DiffHunksToggled => {
19888                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19889            }
19890            multi_buffer::Event::LanguageChanged(buffer_id) => {
19891                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19892                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19893                cx.emit(EditorEvent::Reparsed(*buffer_id));
19894                cx.notify();
19895            }
19896            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19897            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19898            multi_buffer::Event::FileHandleChanged
19899            | multi_buffer::Event::Reloaded
19900            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19901            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19902            multi_buffer::Event::DiagnosticsUpdated => {
19903                self.update_diagnostics_state(window, cx);
19904            }
19905            _ => {}
19906        };
19907    }
19908
19909    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19910        if !self.diagnostics_enabled() {
19911            return;
19912        }
19913        self.refresh_active_diagnostics(cx);
19914        self.refresh_inline_diagnostics(true, window, cx);
19915        self.scrollbar_marker_state.dirty = true;
19916        cx.notify();
19917    }
19918
19919    pub fn start_temporary_diff_override(&mut self) {
19920        self.load_diff_task.take();
19921        self.temporary_diff_override = true;
19922    }
19923
19924    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19925        self.temporary_diff_override = false;
19926        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19927        self.buffer.update(cx, |buffer, cx| {
19928            buffer.set_all_diff_hunks_collapsed(cx);
19929        });
19930
19931        if let Some(project) = self.project.clone() {
19932            self.load_diff_task = Some(
19933                update_uncommitted_diff_for_buffer(
19934                    cx.entity(),
19935                    &project,
19936                    self.buffer.read(cx).all_buffers(),
19937                    self.buffer.clone(),
19938                    cx,
19939                )
19940                .shared(),
19941            );
19942        }
19943    }
19944
19945    fn on_display_map_changed(
19946        &mut self,
19947        _: Entity<DisplayMap>,
19948        _: &mut Window,
19949        cx: &mut Context<Self>,
19950    ) {
19951        cx.notify();
19952    }
19953
19954    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19955        if self.diagnostics_enabled() {
19956            let new_severity = EditorSettings::get_global(cx)
19957                .diagnostics_max_severity
19958                .unwrap_or(DiagnosticSeverity::Hint);
19959            self.set_max_diagnostics_severity(new_severity, cx);
19960        }
19961        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19962        self.update_edit_prediction_settings(cx);
19963        self.refresh_inline_completion(true, false, window, cx);
19964        self.refresh_inline_values(cx);
19965        self.refresh_inlay_hints(
19966            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19967                self.selections.newest_anchor().head(),
19968                &self.buffer.read(cx).snapshot(cx),
19969                cx,
19970            )),
19971            cx,
19972        );
19973
19974        let old_cursor_shape = self.cursor_shape;
19975
19976        {
19977            let editor_settings = EditorSettings::get_global(cx);
19978            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19979            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19980            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19981            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19982        }
19983
19984        if old_cursor_shape != self.cursor_shape {
19985            cx.emit(EditorEvent::CursorShapeChanged);
19986        }
19987
19988        let project_settings = ProjectSettings::get_global(cx);
19989        self.serialize_dirty_buffers =
19990            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19991
19992        if self.mode.is_full() {
19993            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19994            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19995            if self.show_inline_diagnostics != show_inline_diagnostics {
19996                self.show_inline_diagnostics = show_inline_diagnostics;
19997                self.refresh_inline_diagnostics(false, window, cx);
19998            }
19999
20000            if self.git_blame_inline_enabled != inline_blame_enabled {
20001                self.toggle_git_blame_inline_internal(false, window, cx);
20002            }
20003
20004            let minimap_settings = EditorSettings::get_global(cx).minimap;
20005            if self.minimap_visibility != MinimapVisibility::Disabled {
20006                if self.minimap_visibility.settings_visibility()
20007                    != minimap_settings.minimap_enabled()
20008                {
20009                    self.set_minimap_visibility(
20010                        MinimapVisibility::for_mode(self.mode(), cx),
20011                        window,
20012                        cx,
20013                    );
20014                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20015                    minimap_entity.update(cx, |minimap_editor, cx| {
20016                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20017                    })
20018                }
20019            }
20020        }
20021
20022        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20023            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20024        }) {
20025            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20026                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20027            }
20028            self.refresh_colors(false, None, window, cx);
20029        }
20030
20031        cx.notify();
20032    }
20033
20034    pub fn set_searchable(&mut self, searchable: bool) {
20035        self.searchable = searchable;
20036    }
20037
20038    pub fn searchable(&self) -> bool {
20039        self.searchable
20040    }
20041
20042    fn open_proposed_changes_editor(
20043        &mut self,
20044        _: &OpenProposedChangesEditor,
20045        window: &mut Window,
20046        cx: &mut Context<Self>,
20047    ) {
20048        let Some(workspace) = self.workspace() else {
20049            cx.propagate();
20050            return;
20051        };
20052
20053        let selections = self.selections.all::<usize>(cx);
20054        let multi_buffer = self.buffer.read(cx);
20055        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20056        let mut new_selections_by_buffer = HashMap::default();
20057        for selection in selections {
20058            for (buffer, range, _) in
20059                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20060            {
20061                let mut range = range.to_point(buffer);
20062                range.start.column = 0;
20063                range.end.column = buffer.line_len(range.end.row);
20064                new_selections_by_buffer
20065                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20066                    .or_insert(Vec::new())
20067                    .push(range)
20068            }
20069        }
20070
20071        let proposed_changes_buffers = new_selections_by_buffer
20072            .into_iter()
20073            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20074            .collect::<Vec<_>>();
20075        let proposed_changes_editor = cx.new(|cx| {
20076            ProposedChangesEditor::new(
20077                "Proposed changes",
20078                proposed_changes_buffers,
20079                self.project.clone(),
20080                window,
20081                cx,
20082            )
20083        });
20084
20085        window.defer(cx, move |window, cx| {
20086            workspace.update(cx, |workspace, cx| {
20087                workspace.active_pane().update(cx, |pane, cx| {
20088                    pane.add_item(
20089                        Box::new(proposed_changes_editor),
20090                        true,
20091                        true,
20092                        None,
20093                        window,
20094                        cx,
20095                    );
20096                });
20097            });
20098        });
20099    }
20100
20101    pub fn open_excerpts_in_split(
20102        &mut self,
20103        _: &OpenExcerptsSplit,
20104        window: &mut Window,
20105        cx: &mut Context<Self>,
20106    ) {
20107        self.open_excerpts_common(None, true, window, cx)
20108    }
20109
20110    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20111        self.open_excerpts_common(None, false, window, cx)
20112    }
20113
20114    fn open_excerpts_common(
20115        &mut self,
20116        jump_data: Option<JumpData>,
20117        split: bool,
20118        window: &mut Window,
20119        cx: &mut Context<Self>,
20120    ) {
20121        let Some(workspace) = self.workspace() else {
20122            cx.propagate();
20123            return;
20124        };
20125
20126        if self.buffer.read(cx).is_singleton() {
20127            cx.propagate();
20128            return;
20129        }
20130
20131        let mut new_selections_by_buffer = HashMap::default();
20132        match &jump_data {
20133            Some(JumpData::MultiBufferPoint {
20134                excerpt_id,
20135                position,
20136                anchor,
20137                line_offset_from_top,
20138            }) => {
20139                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20140                if let Some(buffer) = multi_buffer_snapshot
20141                    .buffer_id_for_excerpt(*excerpt_id)
20142                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20143                {
20144                    let buffer_snapshot = buffer.read(cx).snapshot();
20145                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20146                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20147                    } else {
20148                        buffer_snapshot.clip_point(*position, Bias::Left)
20149                    };
20150                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20151                    new_selections_by_buffer.insert(
20152                        buffer,
20153                        (
20154                            vec![jump_to_offset..jump_to_offset],
20155                            Some(*line_offset_from_top),
20156                        ),
20157                    );
20158                }
20159            }
20160            Some(JumpData::MultiBufferRow {
20161                row,
20162                line_offset_from_top,
20163            }) => {
20164                let point = MultiBufferPoint::new(row.0, 0);
20165                if let Some((buffer, buffer_point, _)) =
20166                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20167                {
20168                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20169                    new_selections_by_buffer
20170                        .entry(buffer)
20171                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20172                        .0
20173                        .push(buffer_offset..buffer_offset)
20174                }
20175            }
20176            None => {
20177                let selections = self.selections.all::<usize>(cx);
20178                let multi_buffer = self.buffer.read(cx);
20179                for selection in selections {
20180                    for (snapshot, range, _, anchor) in multi_buffer
20181                        .snapshot(cx)
20182                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20183                    {
20184                        if let Some(anchor) = anchor {
20185                            // selection is in a deleted hunk
20186                            let Some(buffer_id) = anchor.buffer_id else {
20187                                continue;
20188                            };
20189                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20190                                continue;
20191                            };
20192                            let offset = text::ToOffset::to_offset(
20193                                &anchor.text_anchor,
20194                                &buffer_handle.read(cx).snapshot(),
20195                            );
20196                            let range = offset..offset;
20197                            new_selections_by_buffer
20198                                .entry(buffer_handle)
20199                                .or_insert((Vec::new(), None))
20200                                .0
20201                                .push(range)
20202                        } else {
20203                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20204                            else {
20205                                continue;
20206                            };
20207                            new_selections_by_buffer
20208                                .entry(buffer_handle)
20209                                .or_insert((Vec::new(), None))
20210                                .0
20211                                .push(range)
20212                        }
20213                    }
20214                }
20215            }
20216        }
20217
20218        new_selections_by_buffer
20219            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20220
20221        if new_selections_by_buffer.is_empty() {
20222            return;
20223        }
20224
20225        // We defer the pane interaction because we ourselves are a workspace item
20226        // and activating a new item causes the pane to call a method on us reentrantly,
20227        // which panics if we're on the stack.
20228        window.defer(cx, move |window, cx| {
20229            workspace.update(cx, |workspace, cx| {
20230                let pane = if split {
20231                    workspace.adjacent_pane(window, cx)
20232                } else {
20233                    workspace.active_pane().clone()
20234                };
20235
20236                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20237                    let editor = buffer
20238                        .read(cx)
20239                        .file()
20240                        .is_none()
20241                        .then(|| {
20242                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20243                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20244                            // Instead, we try to activate the existing editor in the pane first.
20245                            let (editor, pane_item_index) =
20246                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20247                                    let editor = item.downcast::<Editor>()?;
20248                                    let singleton_buffer =
20249                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20250                                    if singleton_buffer == buffer {
20251                                        Some((editor, i))
20252                                    } else {
20253                                        None
20254                                    }
20255                                })?;
20256                            pane.update(cx, |pane, cx| {
20257                                pane.activate_item(pane_item_index, true, true, window, cx)
20258                            });
20259                            Some(editor)
20260                        })
20261                        .flatten()
20262                        .unwrap_or_else(|| {
20263                            workspace.open_project_item::<Self>(
20264                                pane.clone(),
20265                                buffer,
20266                                true,
20267                                true,
20268                                window,
20269                                cx,
20270                            )
20271                        });
20272
20273                    editor.update(cx, |editor, cx| {
20274                        let autoscroll = match scroll_offset {
20275                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20276                            None => Autoscroll::newest(),
20277                        };
20278                        let nav_history = editor.nav_history.take();
20279                        editor.change_selections(
20280                            SelectionEffects::scroll(autoscroll),
20281                            window,
20282                            cx,
20283                            |s| {
20284                                s.select_ranges(ranges);
20285                            },
20286                        );
20287                        editor.nav_history = nav_history;
20288                    });
20289                }
20290            })
20291        });
20292    }
20293
20294    // For now, don't allow opening excerpts in buffers that aren't backed by
20295    // regular project files.
20296    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20297        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20298    }
20299
20300    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20301        let snapshot = self.buffer.read(cx).read(cx);
20302        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20303        Some(
20304            ranges
20305                .iter()
20306                .map(move |range| {
20307                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20308                })
20309                .collect(),
20310        )
20311    }
20312
20313    fn selection_replacement_ranges(
20314        &self,
20315        range: Range<OffsetUtf16>,
20316        cx: &mut App,
20317    ) -> Vec<Range<OffsetUtf16>> {
20318        let selections = self.selections.all::<OffsetUtf16>(cx);
20319        let newest_selection = selections
20320            .iter()
20321            .max_by_key(|selection| selection.id)
20322            .unwrap();
20323        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20324        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20325        let snapshot = self.buffer.read(cx).read(cx);
20326        selections
20327            .into_iter()
20328            .map(|mut selection| {
20329                selection.start.0 =
20330                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20331                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20332                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20333                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20334            })
20335            .collect()
20336    }
20337
20338    fn report_editor_event(
20339        &self,
20340        event_type: &'static str,
20341        file_extension: Option<String>,
20342        cx: &App,
20343    ) {
20344        if cfg!(any(test, feature = "test-support")) {
20345            return;
20346        }
20347
20348        let Some(project) = &self.project else { return };
20349
20350        // If None, we are in a file without an extension
20351        let file = self
20352            .buffer
20353            .read(cx)
20354            .as_singleton()
20355            .and_then(|b| b.read(cx).file());
20356        let file_extension = file_extension.or(file
20357            .as_ref()
20358            .and_then(|file| Path::new(file.file_name(cx)).extension())
20359            .and_then(|e| e.to_str())
20360            .map(|a| a.to_string()));
20361
20362        let vim_mode = vim_enabled(cx);
20363
20364        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20365        let copilot_enabled = edit_predictions_provider
20366            == language::language_settings::EditPredictionProvider::Copilot;
20367        let copilot_enabled_for_language = self
20368            .buffer
20369            .read(cx)
20370            .language_settings(cx)
20371            .show_edit_predictions;
20372
20373        let project = project.read(cx);
20374        telemetry::event!(
20375            event_type,
20376            file_extension,
20377            vim_mode,
20378            copilot_enabled,
20379            copilot_enabled_for_language,
20380            edit_predictions_provider,
20381            is_via_ssh = project.is_via_ssh(),
20382        );
20383    }
20384
20385    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20386    /// with each line being an array of {text, highlight} objects.
20387    fn copy_highlight_json(
20388        &mut self,
20389        _: &CopyHighlightJson,
20390        window: &mut Window,
20391        cx: &mut Context<Self>,
20392    ) {
20393        #[derive(Serialize)]
20394        struct Chunk<'a> {
20395            text: String,
20396            highlight: Option<&'a str>,
20397        }
20398
20399        let snapshot = self.buffer.read(cx).snapshot(cx);
20400        let range = self
20401            .selected_text_range(false, window, cx)
20402            .and_then(|selection| {
20403                if selection.range.is_empty() {
20404                    None
20405                } else {
20406                    Some(selection.range)
20407                }
20408            })
20409            .unwrap_or_else(|| 0..snapshot.len());
20410
20411        let chunks = snapshot.chunks(range, true);
20412        let mut lines = Vec::new();
20413        let mut line: VecDeque<Chunk> = VecDeque::new();
20414
20415        let Some(style) = self.style.as_ref() else {
20416            return;
20417        };
20418
20419        for chunk in chunks {
20420            let highlight = chunk
20421                .syntax_highlight_id
20422                .and_then(|id| id.name(&style.syntax));
20423            let mut chunk_lines = chunk.text.split('\n').peekable();
20424            while let Some(text) = chunk_lines.next() {
20425                let mut merged_with_last_token = false;
20426                if let Some(last_token) = line.back_mut() {
20427                    if last_token.highlight == highlight {
20428                        last_token.text.push_str(text);
20429                        merged_with_last_token = true;
20430                    }
20431                }
20432
20433                if !merged_with_last_token {
20434                    line.push_back(Chunk {
20435                        text: text.into(),
20436                        highlight,
20437                    });
20438                }
20439
20440                if chunk_lines.peek().is_some() {
20441                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20442                        line.pop_front();
20443                    }
20444                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20445                        line.pop_back();
20446                    }
20447
20448                    lines.push(mem::take(&mut line));
20449                }
20450            }
20451        }
20452
20453        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20454            return;
20455        };
20456        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20457    }
20458
20459    pub fn open_context_menu(
20460        &mut self,
20461        _: &OpenContextMenu,
20462        window: &mut Window,
20463        cx: &mut Context<Self>,
20464    ) {
20465        self.request_autoscroll(Autoscroll::newest(), cx);
20466        let position = self.selections.newest_display(cx).start;
20467        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20468    }
20469
20470    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20471        &self.inlay_hint_cache
20472    }
20473
20474    pub fn replay_insert_event(
20475        &mut self,
20476        text: &str,
20477        relative_utf16_range: Option<Range<isize>>,
20478        window: &mut Window,
20479        cx: &mut Context<Self>,
20480    ) {
20481        if !self.input_enabled {
20482            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20483            return;
20484        }
20485        if let Some(relative_utf16_range) = relative_utf16_range {
20486            let selections = self.selections.all::<OffsetUtf16>(cx);
20487            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20488                let new_ranges = selections.into_iter().map(|range| {
20489                    let start = OffsetUtf16(
20490                        range
20491                            .head()
20492                            .0
20493                            .saturating_add_signed(relative_utf16_range.start),
20494                    );
20495                    let end = OffsetUtf16(
20496                        range
20497                            .head()
20498                            .0
20499                            .saturating_add_signed(relative_utf16_range.end),
20500                    );
20501                    start..end
20502                });
20503                s.select_ranges(new_ranges);
20504            });
20505        }
20506
20507        self.handle_input(text, window, cx);
20508    }
20509
20510    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20511        let Some(provider) = self.semantics_provider.as_ref() else {
20512            return false;
20513        };
20514
20515        let mut supports = false;
20516        self.buffer().update(cx, |this, cx| {
20517            this.for_each_buffer(|buffer| {
20518                supports |= provider.supports_inlay_hints(buffer, cx);
20519            });
20520        });
20521
20522        supports
20523    }
20524
20525    pub fn is_focused(&self, window: &Window) -> bool {
20526        self.focus_handle.is_focused(window)
20527    }
20528
20529    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20530        cx.emit(EditorEvent::Focused);
20531
20532        if let Some(descendant) = self
20533            .last_focused_descendant
20534            .take()
20535            .and_then(|descendant| descendant.upgrade())
20536        {
20537            window.focus(&descendant);
20538        } else {
20539            if let Some(blame) = self.blame.as_ref() {
20540                blame.update(cx, GitBlame::focus)
20541            }
20542
20543            self.blink_manager.update(cx, BlinkManager::enable);
20544            self.show_cursor_names(window, cx);
20545            self.buffer.update(cx, |buffer, cx| {
20546                buffer.finalize_last_transaction(cx);
20547                if self.leader_id.is_none() {
20548                    buffer.set_active_selections(
20549                        &self.selections.disjoint_anchors(),
20550                        self.selections.line_mode,
20551                        self.cursor_shape,
20552                        cx,
20553                    );
20554                }
20555            });
20556        }
20557    }
20558
20559    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20560        cx.emit(EditorEvent::FocusedIn)
20561    }
20562
20563    fn handle_focus_out(
20564        &mut self,
20565        event: FocusOutEvent,
20566        _window: &mut Window,
20567        cx: &mut Context<Self>,
20568    ) {
20569        if event.blurred != self.focus_handle {
20570            self.last_focused_descendant = Some(event.blurred);
20571        }
20572        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20573    }
20574
20575    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20576        self.blink_manager.update(cx, BlinkManager::disable);
20577        self.buffer
20578            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20579
20580        if let Some(blame) = self.blame.as_ref() {
20581            blame.update(cx, GitBlame::blur)
20582        }
20583        if !self.hover_state.focused(window, cx) {
20584            hide_hover(self, cx);
20585        }
20586        if !self
20587            .context_menu
20588            .borrow()
20589            .as_ref()
20590            .is_some_and(|context_menu| context_menu.focused(window, cx))
20591        {
20592            self.hide_context_menu(window, cx);
20593        }
20594        self.discard_inline_completion(false, cx);
20595        cx.emit(EditorEvent::Blurred);
20596        cx.notify();
20597    }
20598
20599    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20600        let mut pending: String = window
20601            .pending_input_keystrokes()
20602            .into_iter()
20603            .flatten()
20604            .filter_map(|keystroke| {
20605                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20606                    keystroke.key_char.clone()
20607                } else {
20608                    None
20609                }
20610            })
20611            .collect();
20612
20613        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20614            pending = "".to_string();
20615        }
20616
20617        let existing_pending = self
20618            .text_highlights::<PendingInput>(cx)
20619            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20620        if existing_pending.is_none() && pending.is_empty() {
20621            return;
20622        }
20623        let transaction =
20624            self.transact(window, cx, |this, window, cx| {
20625                let selections = this.selections.all::<usize>(cx);
20626                let edits = selections
20627                    .iter()
20628                    .map(|selection| (selection.end..selection.end, pending.clone()));
20629                this.edit(edits, cx);
20630                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20631                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20632                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20633                    }));
20634                });
20635                if let Some(existing_ranges) = existing_pending {
20636                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20637                    this.edit(edits, cx);
20638                }
20639            });
20640
20641        let snapshot = self.snapshot(window, cx);
20642        let ranges = self
20643            .selections
20644            .all::<usize>(cx)
20645            .into_iter()
20646            .map(|selection| {
20647                snapshot.buffer_snapshot.anchor_after(selection.end)
20648                    ..snapshot
20649                        .buffer_snapshot
20650                        .anchor_before(selection.end + pending.len())
20651            })
20652            .collect();
20653
20654        if pending.is_empty() {
20655            self.clear_highlights::<PendingInput>(cx);
20656        } else {
20657            self.highlight_text::<PendingInput>(
20658                ranges,
20659                HighlightStyle {
20660                    underline: Some(UnderlineStyle {
20661                        thickness: px(1.),
20662                        color: None,
20663                        wavy: false,
20664                    }),
20665                    ..Default::default()
20666                },
20667                cx,
20668            );
20669        }
20670
20671        self.ime_transaction = self.ime_transaction.or(transaction);
20672        if let Some(transaction) = self.ime_transaction {
20673            self.buffer.update(cx, |buffer, cx| {
20674                buffer.group_until_transaction(transaction, cx);
20675            });
20676        }
20677
20678        if self.text_highlights::<PendingInput>(cx).is_none() {
20679            self.ime_transaction.take();
20680        }
20681    }
20682
20683    pub fn register_action_renderer(
20684        &mut self,
20685        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20686    ) -> Subscription {
20687        let id = self.next_editor_action_id.post_inc();
20688        self.editor_actions
20689            .borrow_mut()
20690            .insert(id, Box::new(listener));
20691
20692        let editor_actions = self.editor_actions.clone();
20693        Subscription::new(move || {
20694            editor_actions.borrow_mut().remove(&id);
20695        })
20696    }
20697
20698    pub fn register_action<A: Action>(
20699        &mut self,
20700        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20701    ) -> Subscription {
20702        let id = self.next_editor_action_id.post_inc();
20703        let listener = Arc::new(listener);
20704        self.editor_actions.borrow_mut().insert(
20705            id,
20706            Box::new(move |_, window, _| {
20707                let listener = listener.clone();
20708                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20709                    let action = action.downcast_ref().unwrap();
20710                    if phase == DispatchPhase::Bubble {
20711                        listener(action, window, cx)
20712                    }
20713                })
20714            }),
20715        );
20716
20717        let editor_actions = self.editor_actions.clone();
20718        Subscription::new(move || {
20719            editor_actions.borrow_mut().remove(&id);
20720        })
20721    }
20722
20723    pub fn file_header_size(&self) -> u32 {
20724        FILE_HEADER_HEIGHT
20725    }
20726
20727    pub fn restore(
20728        &mut self,
20729        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20730        window: &mut Window,
20731        cx: &mut Context<Self>,
20732    ) {
20733        let workspace = self.workspace();
20734        let project = self.project.as_ref();
20735        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20736            let mut tasks = Vec::new();
20737            for (buffer_id, changes) in revert_changes {
20738                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20739                    buffer.update(cx, |buffer, cx| {
20740                        buffer.edit(
20741                            changes
20742                                .into_iter()
20743                                .map(|(range, text)| (range, text.to_string())),
20744                            None,
20745                            cx,
20746                        );
20747                    });
20748
20749                    if let Some(project) =
20750                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20751                    {
20752                        project.update(cx, |project, cx| {
20753                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20754                        })
20755                    }
20756                }
20757            }
20758            tasks
20759        });
20760        cx.spawn_in(window, async move |_, cx| {
20761            for (buffer, task) in save_tasks {
20762                let result = task.await;
20763                if result.is_err() {
20764                    let Some(path) = buffer
20765                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20766                        .ok()
20767                    else {
20768                        continue;
20769                    };
20770                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20771                        let Some(task) = cx
20772                            .update_window_entity(&workspace, |workspace, window, cx| {
20773                                workspace
20774                                    .open_path_preview(path, None, false, false, false, window, cx)
20775                            })
20776                            .ok()
20777                        else {
20778                            continue;
20779                        };
20780                        task.await.log_err();
20781                    }
20782                }
20783            }
20784        })
20785        .detach();
20786        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20787            selections.refresh()
20788        });
20789    }
20790
20791    pub fn to_pixel_point(
20792        &self,
20793        source: multi_buffer::Anchor,
20794        editor_snapshot: &EditorSnapshot,
20795        window: &mut Window,
20796    ) -> Option<gpui::Point<Pixels>> {
20797        let source_point = source.to_display_point(editor_snapshot);
20798        self.display_to_pixel_point(source_point, editor_snapshot, window)
20799    }
20800
20801    pub fn display_to_pixel_point(
20802        &self,
20803        source: DisplayPoint,
20804        editor_snapshot: &EditorSnapshot,
20805        window: &mut Window,
20806    ) -> Option<gpui::Point<Pixels>> {
20807        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20808        let text_layout_details = self.text_layout_details(window);
20809        let scroll_top = text_layout_details
20810            .scroll_anchor
20811            .scroll_position(editor_snapshot)
20812            .y;
20813
20814        if source.row().as_f32() < scroll_top.floor() {
20815            return None;
20816        }
20817        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20818        let source_y = line_height * (source.row().as_f32() - scroll_top);
20819        Some(gpui::Point::new(source_x, source_y))
20820    }
20821
20822    pub fn has_visible_completions_menu(&self) -> bool {
20823        !self.edit_prediction_preview_is_active()
20824            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20825                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20826            })
20827    }
20828
20829    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20830        if self.mode.is_minimap() {
20831            return;
20832        }
20833        self.addons
20834            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20835    }
20836
20837    pub fn unregister_addon<T: Addon>(&mut self) {
20838        self.addons.remove(&std::any::TypeId::of::<T>());
20839    }
20840
20841    pub fn addon<T: Addon>(&self) -> Option<&T> {
20842        let type_id = std::any::TypeId::of::<T>();
20843        self.addons
20844            .get(&type_id)
20845            .and_then(|item| item.to_any().downcast_ref::<T>())
20846    }
20847
20848    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20849        let type_id = std::any::TypeId::of::<T>();
20850        self.addons
20851            .get_mut(&type_id)
20852            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20853    }
20854
20855    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20856        let text_layout_details = self.text_layout_details(window);
20857        let style = &text_layout_details.editor_style;
20858        let font_id = window.text_system().resolve_font(&style.text.font());
20859        let font_size = style.text.font_size.to_pixels(window.rem_size());
20860        let line_height = style.text.line_height_in_pixels(window.rem_size());
20861        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20862        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20863
20864        CharacterDimensions {
20865            em_width,
20866            em_advance,
20867            line_height,
20868        }
20869    }
20870
20871    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20872        self.load_diff_task.clone()
20873    }
20874
20875    fn read_metadata_from_db(
20876        &mut self,
20877        item_id: u64,
20878        workspace_id: WorkspaceId,
20879        window: &mut Window,
20880        cx: &mut Context<Editor>,
20881    ) {
20882        if self.is_singleton(cx)
20883            && !self.mode.is_minimap()
20884            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20885        {
20886            let buffer_snapshot = OnceCell::new();
20887
20888            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20889                if !folds.is_empty() {
20890                    let snapshot =
20891                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20892                    self.fold_ranges(
20893                        folds
20894                            .into_iter()
20895                            .map(|(start, end)| {
20896                                snapshot.clip_offset(start, Bias::Left)
20897                                    ..snapshot.clip_offset(end, Bias::Right)
20898                            })
20899                            .collect(),
20900                        false,
20901                        window,
20902                        cx,
20903                    );
20904                }
20905            }
20906
20907            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20908                if !selections.is_empty() {
20909                    let snapshot =
20910                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20911                    // skip adding the initial selection to selection history
20912                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20913                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20914                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20915                            snapshot.clip_offset(start, Bias::Left)
20916                                ..snapshot.clip_offset(end, Bias::Right)
20917                        }));
20918                    });
20919                    self.selection_history.mode = SelectionHistoryMode::Normal;
20920                }
20921            };
20922        }
20923
20924        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20925    }
20926
20927    fn update_lsp_data(
20928        &mut self,
20929        ignore_cache: bool,
20930        for_buffer: Option<BufferId>,
20931        window: &mut Window,
20932        cx: &mut Context<'_, Self>,
20933    ) {
20934        self.pull_diagnostics(for_buffer, window, cx);
20935        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20936    }
20937}
20938
20939fn vim_enabled(cx: &App) -> bool {
20940    cx.global::<SettingsStore>()
20941        .raw_user_settings()
20942        .get("vim_mode")
20943        == Some(&serde_json::Value::Bool(true))
20944}
20945
20946fn process_completion_for_edit(
20947    completion: &Completion,
20948    intent: CompletionIntent,
20949    buffer: &Entity<Buffer>,
20950    cursor_position: &text::Anchor,
20951    cx: &mut Context<Editor>,
20952) -> CompletionEdit {
20953    let buffer = buffer.read(cx);
20954    let buffer_snapshot = buffer.snapshot();
20955    let (snippet, new_text) = if completion.is_snippet() {
20956        // Workaround for typescript language server issues so that methods don't expand within
20957        // strings and functions with type expressions. The previous point is used because the query
20958        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20959        let mut snippet_source = completion.new_text.clone();
20960        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20961        previous_point.column = previous_point.column.saturating_sub(1);
20962        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20963            if scope.prefers_label_for_snippet_in_completion() {
20964                if let Some(label) = completion.label() {
20965                    if matches!(
20966                        completion.kind(),
20967                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20968                    ) {
20969                        snippet_source = label;
20970                    }
20971                }
20972            }
20973        }
20974        match Snippet::parse(&snippet_source).log_err() {
20975            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20976            None => (None, completion.new_text.clone()),
20977        }
20978    } else {
20979        (None, completion.new_text.clone())
20980    };
20981
20982    let mut range_to_replace = {
20983        let replace_range = &completion.replace_range;
20984        if let CompletionSource::Lsp {
20985            insert_range: Some(insert_range),
20986            ..
20987        } = &completion.source
20988        {
20989            debug_assert_eq!(
20990                insert_range.start, replace_range.start,
20991                "insert_range and replace_range should start at the same position"
20992            );
20993            debug_assert!(
20994                insert_range
20995                    .start
20996                    .cmp(&cursor_position, &buffer_snapshot)
20997                    .is_le(),
20998                "insert_range should start before or at cursor position"
20999            );
21000            debug_assert!(
21001                replace_range
21002                    .start
21003                    .cmp(&cursor_position, &buffer_snapshot)
21004                    .is_le(),
21005                "replace_range should start before or at cursor position"
21006            );
21007            debug_assert!(
21008                insert_range
21009                    .end
21010                    .cmp(&cursor_position, &buffer_snapshot)
21011                    .is_le(),
21012                "insert_range should end before or at cursor position"
21013            );
21014
21015            let should_replace = match intent {
21016                CompletionIntent::CompleteWithInsert => false,
21017                CompletionIntent::CompleteWithReplace => true,
21018                CompletionIntent::Complete | CompletionIntent::Compose => {
21019                    let insert_mode =
21020                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21021                            .completions
21022                            .lsp_insert_mode;
21023                    match insert_mode {
21024                        LspInsertMode::Insert => false,
21025                        LspInsertMode::Replace => true,
21026                        LspInsertMode::ReplaceSubsequence => {
21027                            let mut text_to_replace = buffer.chars_for_range(
21028                                buffer.anchor_before(replace_range.start)
21029                                    ..buffer.anchor_after(replace_range.end),
21030                            );
21031                            let mut current_needle = text_to_replace.next();
21032                            for haystack_ch in completion.label.text.chars() {
21033                                if let Some(needle_ch) = current_needle {
21034                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21035                                        current_needle = text_to_replace.next();
21036                                    }
21037                                }
21038                            }
21039                            current_needle.is_none()
21040                        }
21041                        LspInsertMode::ReplaceSuffix => {
21042                            if replace_range
21043                                .end
21044                                .cmp(&cursor_position, &buffer_snapshot)
21045                                .is_gt()
21046                            {
21047                                let range_after_cursor = *cursor_position..replace_range.end;
21048                                let text_after_cursor = buffer
21049                                    .text_for_range(
21050                                        buffer.anchor_before(range_after_cursor.start)
21051                                            ..buffer.anchor_after(range_after_cursor.end),
21052                                    )
21053                                    .collect::<String>()
21054                                    .to_ascii_lowercase();
21055                                completion
21056                                    .label
21057                                    .text
21058                                    .to_ascii_lowercase()
21059                                    .ends_with(&text_after_cursor)
21060                            } else {
21061                                true
21062                            }
21063                        }
21064                    }
21065                }
21066            };
21067
21068            if should_replace {
21069                replace_range.clone()
21070            } else {
21071                insert_range.clone()
21072            }
21073        } else {
21074            replace_range.clone()
21075        }
21076    };
21077
21078    if range_to_replace
21079        .end
21080        .cmp(&cursor_position, &buffer_snapshot)
21081        .is_lt()
21082    {
21083        range_to_replace.end = *cursor_position;
21084    }
21085
21086    CompletionEdit {
21087        new_text,
21088        replace_range: range_to_replace.to_offset(&buffer),
21089        snippet,
21090    }
21091}
21092
21093struct CompletionEdit {
21094    new_text: String,
21095    replace_range: Range<usize>,
21096    snippet: Option<Snippet>,
21097}
21098
21099fn insert_extra_newline_brackets(
21100    buffer: &MultiBufferSnapshot,
21101    range: Range<usize>,
21102    language: &language::LanguageScope,
21103) -> bool {
21104    let leading_whitespace_len = buffer
21105        .reversed_chars_at(range.start)
21106        .take_while(|c| c.is_whitespace() && *c != '\n')
21107        .map(|c| c.len_utf8())
21108        .sum::<usize>();
21109    let trailing_whitespace_len = buffer
21110        .chars_at(range.end)
21111        .take_while(|c| c.is_whitespace() && *c != '\n')
21112        .map(|c| c.len_utf8())
21113        .sum::<usize>();
21114    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21115
21116    language.brackets().any(|(pair, enabled)| {
21117        let pair_start = pair.start.trim_end();
21118        let pair_end = pair.end.trim_start();
21119
21120        enabled
21121            && pair.newline
21122            && buffer.contains_str_at(range.end, pair_end)
21123            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21124    })
21125}
21126
21127fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21128    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21129        [(buffer, range, _)] => (*buffer, range.clone()),
21130        _ => return false,
21131    };
21132    let pair = {
21133        let mut result: Option<BracketMatch> = None;
21134
21135        for pair in buffer
21136            .all_bracket_ranges(range.clone())
21137            .filter(move |pair| {
21138                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21139            })
21140        {
21141            let len = pair.close_range.end - pair.open_range.start;
21142
21143            if let Some(existing) = &result {
21144                let existing_len = existing.close_range.end - existing.open_range.start;
21145                if len > existing_len {
21146                    continue;
21147                }
21148            }
21149
21150            result = Some(pair);
21151        }
21152
21153        result
21154    };
21155    let Some(pair) = pair else {
21156        return false;
21157    };
21158    pair.newline_only
21159        && buffer
21160            .chars_for_range(pair.open_range.end..range.start)
21161            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21162            .all(|c| c.is_whitespace() && c != '\n')
21163}
21164
21165fn update_uncommitted_diff_for_buffer(
21166    editor: Entity<Editor>,
21167    project: &Entity<Project>,
21168    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21169    buffer: Entity<MultiBuffer>,
21170    cx: &mut App,
21171) -> Task<()> {
21172    let mut tasks = Vec::new();
21173    project.update(cx, |project, cx| {
21174        for buffer in buffers {
21175            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21176                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21177            }
21178        }
21179    });
21180    cx.spawn(async move |cx| {
21181        let diffs = future::join_all(tasks).await;
21182        if editor
21183            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21184            .unwrap_or(false)
21185        {
21186            return;
21187        }
21188
21189        buffer
21190            .update(cx, |buffer, cx| {
21191                for diff in diffs.into_iter().flatten() {
21192                    buffer.add_diff(diff, cx);
21193                }
21194            })
21195            .ok();
21196    })
21197}
21198
21199fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21200    let tab_size = tab_size.get() as usize;
21201    let mut width = offset;
21202
21203    for ch in text.chars() {
21204        width += if ch == '\t' {
21205            tab_size - (width % tab_size)
21206        } else {
21207            1
21208        };
21209    }
21210
21211    width - offset
21212}
21213
21214#[cfg(test)]
21215mod tests {
21216    use super::*;
21217
21218    #[test]
21219    fn test_string_size_with_expanded_tabs() {
21220        let nz = |val| NonZeroU32::new(val).unwrap();
21221        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21222        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21223        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21224        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21225        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21226        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21227        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21228        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21229    }
21230}
21231
21232/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21233struct WordBreakingTokenizer<'a> {
21234    input: &'a str,
21235}
21236
21237impl<'a> WordBreakingTokenizer<'a> {
21238    fn new(input: &'a str) -> Self {
21239        Self { input }
21240    }
21241}
21242
21243fn is_char_ideographic(ch: char) -> bool {
21244    use unicode_script::Script::*;
21245    use unicode_script::UnicodeScript;
21246    matches!(ch.script(), Han | Tangut | Yi)
21247}
21248
21249fn is_grapheme_ideographic(text: &str) -> bool {
21250    text.chars().any(is_char_ideographic)
21251}
21252
21253fn is_grapheme_whitespace(text: &str) -> bool {
21254    text.chars().any(|x| x.is_whitespace())
21255}
21256
21257fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21258    text.chars().next().map_or(false, |ch| {
21259        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21260    })
21261}
21262
21263#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21264enum WordBreakToken<'a> {
21265    Word { token: &'a str, grapheme_len: usize },
21266    InlineWhitespace { token: &'a str, grapheme_len: usize },
21267    Newline,
21268}
21269
21270impl<'a> Iterator for WordBreakingTokenizer<'a> {
21271    /// Yields a span, the count of graphemes in the token, and whether it was
21272    /// whitespace. Note that it also breaks at word boundaries.
21273    type Item = WordBreakToken<'a>;
21274
21275    fn next(&mut self) -> Option<Self::Item> {
21276        use unicode_segmentation::UnicodeSegmentation;
21277        if self.input.is_empty() {
21278            return None;
21279        }
21280
21281        let mut iter = self.input.graphemes(true).peekable();
21282        let mut offset = 0;
21283        let mut grapheme_len = 0;
21284        if let Some(first_grapheme) = iter.next() {
21285            let is_newline = first_grapheme == "\n";
21286            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21287            offset += first_grapheme.len();
21288            grapheme_len += 1;
21289            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21290                if let Some(grapheme) = iter.peek().copied() {
21291                    if should_stay_with_preceding_ideograph(grapheme) {
21292                        offset += grapheme.len();
21293                        grapheme_len += 1;
21294                    }
21295                }
21296            } else {
21297                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21298                let mut next_word_bound = words.peek().copied();
21299                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21300                    next_word_bound = words.next();
21301                }
21302                while let Some(grapheme) = iter.peek().copied() {
21303                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21304                        break;
21305                    };
21306                    if is_grapheme_whitespace(grapheme) != is_whitespace
21307                        || (grapheme == "\n") != is_newline
21308                    {
21309                        break;
21310                    };
21311                    offset += grapheme.len();
21312                    grapheme_len += 1;
21313                    iter.next();
21314                }
21315            }
21316            let token = &self.input[..offset];
21317            self.input = &self.input[offset..];
21318            if token == "\n" {
21319                Some(WordBreakToken::Newline)
21320            } else if is_whitespace {
21321                Some(WordBreakToken::InlineWhitespace {
21322                    token,
21323                    grapheme_len,
21324                })
21325            } else {
21326                Some(WordBreakToken::Word {
21327                    token,
21328                    grapheme_len,
21329                })
21330            }
21331        } else {
21332            None
21333        }
21334    }
21335}
21336
21337#[test]
21338fn test_word_breaking_tokenizer() {
21339    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21340        ("", &[]),
21341        ("  ", &[whitespace("  ", 2)]),
21342        ("Ʒ", &[word("Ʒ", 1)]),
21343        ("Ǽ", &[word("Ǽ", 1)]),
21344        ("", &[word("", 1)]),
21345        ("⋑⋑", &[word("⋑⋑", 2)]),
21346        (
21347            "原理,进而",
21348            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21349        ),
21350        (
21351            "hello world",
21352            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21353        ),
21354        (
21355            "hello, world",
21356            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21357        ),
21358        (
21359            "  hello world",
21360            &[
21361                whitespace("  ", 2),
21362                word("hello", 5),
21363                whitespace(" ", 1),
21364                word("world", 5),
21365            ],
21366        ),
21367        (
21368            "这是什么 \n 钢笔",
21369            &[
21370                word("", 1),
21371                word("", 1),
21372                word("", 1),
21373                word("", 1),
21374                whitespace(" ", 1),
21375                newline(),
21376                whitespace(" ", 1),
21377                word("", 1),
21378                word("", 1),
21379            ],
21380        ),
21381        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21382    ];
21383
21384    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21385        WordBreakToken::Word {
21386            token,
21387            grapheme_len,
21388        }
21389    }
21390
21391    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21392        WordBreakToken::InlineWhitespace {
21393            token,
21394            grapheme_len,
21395        }
21396    }
21397
21398    fn newline() -> WordBreakToken<'static> {
21399        WordBreakToken::Newline
21400    }
21401
21402    for (input, result) in tests {
21403        assert_eq!(
21404            WordBreakingTokenizer::new(input)
21405                .collect::<Vec<_>>()
21406                .as_slice(),
21407            *result,
21408        );
21409    }
21410}
21411
21412fn wrap_with_prefix(
21413    first_line_prefix: String,
21414    subsequent_lines_prefix: String,
21415    unwrapped_text: String,
21416    wrap_column: usize,
21417    tab_size: NonZeroU32,
21418    preserve_existing_whitespace: bool,
21419) -> String {
21420    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21421    let subsequent_lines_prefix_len =
21422        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21423    let mut wrapped_text = String::new();
21424    let mut current_line = first_line_prefix.clone();
21425    let mut is_first_line = true;
21426
21427    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21428    let mut current_line_len = first_line_prefix_len;
21429    let mut in_whitespace = false;
21430    for token in tokenizer {
21431        let have_preceding_whitespace = in_whitespace;
21432        match token {
21433            WordBreakToken::Word {
21434                token,
21435                grapheme_len,
21436            } => {
21437                in_whitespace = false;
21438                let current_prefix_len = if is_first_line {
21439                    first_line_prefix_len
21440                } else {
21441                    subsequent_lines_prefix_len
21442                };
21443                if current_line_len + grapheme_len > wrap_column
21444                    && current_line_len != current_prefix_len
21445                {
21446                    wrapped_text.push_str(current_line.trim_end());
21447                    wrapped_text.push('\n');
21448                    is_first_line = false;
21449                    current_line = subsequent_lines_prefix.clone();
21450                    current_line_len = subsequent_lines_prefix_len;
21451                }
21452                current_line.push_str(token);
21453                current_line_len += grapheme_len;
21454            }
21455            WordBreakToken::InlineWhitespace {
21456                mut token,
21457                mut grapheme_len,
21458            } => {
21459                in_whitespace = true;
21460                if have_preceding_whitespace && !preserve_existing_whitespace {
21461                    continue;
21462                }
21463                if !preserve_existing_whitespace {
21464                    token = " ";
21465                    grapheme_len = 1;
21466                }
21467                let current_prefix_len = if is_first_line {
21468                    first_line_prefix_len
21469                } else {
21470                    subsequent_lines_prefix_len
21471                };
21472                if current_line_len + grapheme_len > wrap_column {
21473                    wrapped_text.push_str(current_line.trim_end());
21474                    wrapped_text.push('\n');
21475                    is_first_line = false;
21476                    current_line = subsequent_lines_prefix.clone();
21477                    current_line_len = subsequent_lines_prefix_len;
21478                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21479                    current_line.push_str(token);
21480                    current_line_len += grapheme_len;
21481                }
21482            }
21483            WordBreakToken::Newline => {
21484                in_whitespace = true;
21485                let current_prefix_len = if is_first_line {
21486                    first_line_prefix_len
21487                } else {
21488                    subsequent_lines_prefix_len
21489                };
21490                if preserve_existing_whitespace {
21491                    wrapped_text.push_str(current_line.trim_end());
21492                    wrapped_text.push('\n');
21493                    is_first_line = false;
21494                    current_line = subsequent_lines_prefix.clone();
21495                    current_line_len = subsequent_lines_prefix_len;
21496                } else if have_preceding_whitespace {
21497                    continue;
21498                } else if current_line_len + 1 > wrap_column
21499                    && current_line_len != current_prefix_len
21500                {
21501                    wrapped_text.push_str(current_line.trim_end());
21502                    wrapped_text.push('\n');
21503                    is_first_line = false;
21504                    current_line = subsequent_lines_prefix.clone();
21505                    current_line_len = subsequent_lines_prefix_len;
21506                } else if current_line_len != current_prefix_len {
21507                    current_line.push(' ');
21508                    current_line_len += 1;
21509                }
21510            }
21511        }
21512    }
21513
21514    if !current_line.is_empty() {
21515        wrapped_text.push_str(&current_line);
21516    }
21517    wrapped_text
21518}
21519
21520#[test]
21521fn test_wrap_with_prefix() {
21522    assert_eq!(
21523        wrap_with_prefix(
21524            "# ".to_string(),
21525            "# ".to_string(),
21526            "abcdefg".to_string(),
21527            4,
21528            NonZeroU32::new(4).unwrap(),
21529            false,
21530        ),
21531        "# abcdefg"
21532    );
21533    assert_eq!(
21534        wrap_with_prefix(
21535            "".to_string(),
21536            "".to_string(),
21537            "\thello world".to_string(),
21538            8,
21539            NonZeroU32::new(4).unwrap(),
21540            false,
21541        ),
21542        "hello\nworld"
21543    );
21544    assert_eq!(
21545        wrap_with_prefix(
21546            "// ".to_string(),
21547            "// ".to_string(),
21548            "xx \nyy zz aa bb cc".to_string(),
21549            12,
21550            NonZeroU32::new(4).unwrap(),
21551            false,
21552        ),
21553        "// xx yy zz\n// aa bb cc"
21554    );
21555    assert_eq!(
21556        wrap_with_prefix(
21557            String::new(),
21558            String::new(),
21559            "这是什么 \n 钢笔".to_string(),
21560            3,
21561            NonZeroU32::new(4).unwrap(),
21562            false,
21563        ),
21564        "这是什\n么 钢\n"
21565    );
21566}
21567
21568pub trait CollaborationHub {
21569    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21570    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21571    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21572}
21573
21574impl CollaborationHub for Entity<Project> {
21575    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21576        self.read(cx).collaborators()
21577    }
21578
21579    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21580        self.read(cx).user_store().read(cx).participant_indices()
21581    }
21582
21583    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21584        let this = self.read(cx);
21585        let user_ids = this.collaborators().values().map(|c| c.user_id);
21586        this.user_store().read(cx).participant_names(user_ids, cx)
21587    }
21588}
21589
21590pub trait SemanticsProvider {
21591    fn hover(
21592        &self,
21593        buffer: &Entity<Buffer>,
21594        position: text::Anchor,
21595        cx: &mut App,
21596    ) -> Option<Task<Vec<project::Hover>>>;
21597
21598    fn inline_values(
21599        &self,
21600        buffer_handle: Entity<Buffer>,
21601        range: Range<text::Anchor>,
21602        cx: &mut App,
21603    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21604
21605    fn inlay_hints(
21606        &self,
21607        buffer_handle: Entity<Buffer>,
21608        range: Range<text::Anchor>,
21609        cx: &mut App,
21610    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21611
21612    fn resolve_inlay_hint(
21613        &self,
21614        hint: InlayHint,
21615        buffer_handle: Entity<Buffer>,
21616        server_id: LanguageServerId,
21617        cx: &mut App,
21618    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21619
21620    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21621
21622    fn document_highlights(
21623        &self,
21624        buffer: &Entity<Buffer>,
21625        position: text::Anchor,
21626        cx: &mut App,
21627    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21628
21629    fn definitions(
21630        &self,
21631        buffer: &Entity<Buffer>,
21632        position: text::Anchor,
21633        kind: GotoDefinitionKind,
21634        cx: &mut App,
21635    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21636
21637    fn range_for_rename(
21638        &self,
21639        buffer: &Entity<Buffer>,
21640        position: text::Anchor,
21641        cx: &mut App,
21642    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21643
21644    fn perform_rename(
21645        &self,
21646        buffer: &Entity<Buffer>,
21647        position: text::Anchor,
21648        new_name: String,
21649        cx: &mut App,
21650    ) -> Option<Task<Result<ProjectTransaction>>>;
21651}
21652
21653pub trait CompletionProvider {
21654    fn completions(
21655        &self,
21656        excerpt_id: ExcerptId,
21657        buffer: &Entity<Buffer>,
21658        buffer_position: text::Anchor,
21659        trigger: CompletionContext,
21660        window: &mut Window,
21661        cx: &mut Context<Editor>,
21662    ) -> Task<Result<Vec<CompletionResponse>>>;
21663
21664    fn resolve_completions(
21665        &self,
21666        _buffer: Entity<Buffer>,
21667        _completion_indices: Vec<usize>,
21668        _completions: Rc<RefCell<Box<[Completion]>>>,
21669        _cx: &mut Context<Editor>,
21670    ) -> Task<Result<bool>> {
21671        Task::ready(Ok(false))
21672    }
21673
21674    fn apply_additional_edits_for_completion(
21675        &self,
21676        _buffer: Entity<Buffer>,
21677        _completions: Rc<RefCell<Box<[Completion]>>>,
21678        _completion_index: usize,
21679        _push_to_history: bool,
21680        _cx: &mut Context<Editor>,
21681    ) -> Task<Result<Option<language::Transaction>>> {
21682        Task::ready(Ok(None))
21683    }
21684
21685    fn is_completion_trigger(
21686        &self,
21687        buffer: &Entity<Buffer>,
21688        position: language::Anchor,
21689        text: &str,
21690        trigger_in_words: bool,
21691        menu_is_open: bool,
21692        cx: &mut Context<Editor>,
21693    ) -> bool;
21694
21695    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21696
21697    fn sort_completions(&self) -> bool {
21698        true
21699    }
21700
21701    fn filter_completions(&self) -> bool {
21702        true
21703    }
21704}
21705
21706pub trait CodeActionProvider {
21707    fn id(&self) -> Arc<str>;
21708
21709    fn code_actions(
21710        &self,
21711        buffer: &Entity<Buffer>,
21712        range: Range<text::Anchor>,
21713        window: &mut Window,
21714        cx: &mut App,
21715    ) -> Task<Result<Vec<CodeAction>>>;
21716
21717    fn apply_code_action(
21718        &self,
21719        buffer_handle: Entity<Buffer>,
21720        action: CodeAction,
21721        excerpt_id: ExcerptId,
21722        push_to_history: bool,
21723        window: &mut Window,
21724        cx: &mut App,
21725    ) -> Task<Result<ProjectTransaction>>;
21726}
21727
21728impl CodeActionProvider for Entity<Project> {
21729    fn id(&self) -> Arc<str> {
21730        "project".into()
21731    }
21732
21733    fn code_actions(
21734        &self,
21735        buffer: &Entity<Buffer>,
21736        range: Range<text::Anchor>,
21737        _window: &mut Window,
21738        cx: &mut App,
21739    ) -> Task<Result<Vec<CodeAction>>> {
21740        self.update(cx, |project, cx| {
21741            let code_lens = project.code_lens(buffer, range.clone(), cx);
21742            let code_actions = project.code_actions(buffer, range, None, cx);
21743            cx.background_spawn(async move {
21744                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21745                Ok(code_lens
21746                    .context("code lens fetch")?
21747                    .into_iter()
21748                    .chain(code_actions.context("code action fetch")?)
21749                    .collect())
21750            })
21751        })
21752    }
21753
21754    fn apply_code_action(
21755        &self,
21756        buffer_handle: Entity<Buffer>,
21757        action: CodeAction,
21758        _excerpt_id: ExcerptId,
21759        push_to_history: bool,
21760        _window: &mut Window,
21761        cx: &mut App,
21762    ) -> Task<Result<ProjectTransaction>> {
21763        self.update(cx, |project, cx| {
21764            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21765        })
21766    }
21767}
21768
21769fn snippet_completions(
21770    project: &Project,
21771    buffer: &Entity<Buffer>,
21772    buffer_position: text::Anchor,
21773    cx: &mut App,
21774) -> Task<Result<CompletionResponse>> {
21775    let languages = buffer.read(cx).languages_at(buffer_position);
21776    let snippet_store = project.snippets().read(cx);
21777
21778    let scopes: Vec<_> = languages
21779        .iter()
21780        .filter_map(|language| {
21781            let language_name = language.lsp_id();
21782            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21783
21784            if snippets.is_empty() {
21785                None
21786            } else {
21787                Some((language.default_scope(), snippets))
21788            }
21789        })
21790        .collect();
21791
21792    if scopes.is_empty() {
21793        return Task::ready(Ok(CompletionResponse {
21794            completions: vec![],
21795            is_incomplete: false,
21796        }));
21797    }
21798
21799    let snapshot = buffer.read(cx).text_snapshot();
21800    let chars: String = snapshot
21801        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21802        .collect();
21803    let executor = cx.background_executor().clone();
21804
21805    cx.background_spawn(async move {
21806        let mut is_incomplete = false;
21807        let mut completions: Vec<Completion> = Vec::new();
21808        for (scope, snippets) in scopes.into_iter() {
21809            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21810            let mut last_word = chars
21811                .chars()
21812                .take_while(|c| classifier.is_word(*c))
21813                .collect::<String>();
21814            last_word = last_word.chars().rev().collect();
21815
21816            if last_word.is_empty() {
21817                return Ok(CompletionResponse {
21818                    completions: vec![],
21819                    is_incomplete: true,
21820                });
21821            }
21822
21823            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21824            let to_lsp = |point: &text::Anchor| {
21825                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21826                point_to_lsp(end)
21827            };
21828            let lsp_end = to_lsp(&buffer_position);
21829
21830            let candidates = snippets
21831                .iter()
21832                .enumerate()
21833                .flat_map(|(ix, snippet)| {
21834                    snippet
21835                        .prefix
21836                        .iter()
21837                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21838                })
21839                .collect::<Vec<StringMatchCandidate>>();
21840
21841            const MAX_RESULTS: usize = 100;
21842            let mut matches = fuzzy::match_strings(
21843                &candidates,
21844                &last_word,
21845                last_word.chars().any(|c| c.is_uppercase()),
21846                true,
21847                MAX_RESULTS,
21848                &Default::default(),
21849                executor.clone(),
21850            )
21851            .await;
21852
21853            if matches.len() >= MAX_RESULTS {
21854                is_incomplete = true;
21855            }
21856
21857            // Remove all candidates where the query's start does not match the start of any word in the candidate
21858            if let Some(query_start) = last_word.chars().next() {
21859                matches.retain(|string_match| {
21860                    split_words(&string_match.string).any(|word| {
21861                        // Check that the first codepoint of the word as lowercase matches the first
21862                        // codepoint of the query as lowercase
21863                        word.chars()
21864                            .flat_map(|codepoint| codepoint.to_lowercase())
21865                            .zip(query_start.to_lowercase())
21866                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21867                    })
21868                });
21869            }
21870
21871            let matched_strings = matches
21872                .into_iter()
21873                .map(|m| m.string)
21874                .collect::<HashSet<_>>();
21875
21876            completions.extend(snippets.iter().filter_map(|snippet| {
21877                let matching_prefix = snippet
21878                    .prefix
21879                    .iter()
21880                    .find(|prefix| matched_strings.contains(*prefix))?;
21881                let start = as_offset - last_word.len();
21882                let start = snapshot.anchor_before(start);
21883                let range = start..buffer_position;
21884                let lsp_start = to_lsp(&start);
21885                let lsp_range = lsp::Range {
21886                    start: lsp_start,
21887                    end: lsp_end,
21888                };
21889                Some(Completion {
21890                    replace_range: range,
21891                    new_text: snippet.body.clone(),
21892                    source: CompletionSource::Lsp {
21893                        insert_range: None,
21894                        server_id: LanguageServerId(usize::MAX),
21895                        resolved: true,
21896                        lsp_completion: Box::new(lsp::CompletionItem {
21897                            label: snippet.prefix.first().unwrap().clone(),
21898                            kind: Some(CompletionItemKind::SNIPPET),
21899                            label_details: snippet.description.as_ref().map(|description| {
21900                                lsp::CompletionItemLabelDetails {
21901                                    detail: Some(description.clone()),
21902                                    description: None,
21903                                }
21904                            }),
21905                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21906                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21907                                lsp::InsertReplaceEdit {
21908                                    new_text: snippet.body.clone(),
21909                                    insert: lsp_range,
21910                                    replace: lsp_range,
21911                                },
21912                            )),
21913                            filter_text: Some(snippet.body.clone()),
21914                            sort_text: Some(char::MAX.to_string()),
21915                            ..lsp::CompletionItem::default()
21916                        }),
21917                        lsp_defaults: None,
21918                    },
21919                    label: CodeLabel {
21920                        text: matching_prefix.clone(),
21921                        runs: Vec::new(),
21922                        filter_range: 0..matching_prefix.len(),
21923                    },
21924                    icon_path: None,
21925                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21926                        single_line: snippet.name.clone().into(),
21927                        plain_text: snippet
21928                            .description
21929                            .clone()
21930                            .map(|description| description.into()),
21931                    }),
21932                    insert_text_mode: None,
21933                    confirm: None,
21934                })
21935            }))
21936        }
21937
21938        Ok(CompletionResponse {
21939            completions,
21940            is_incomplete,
21941        })
21942    })
21943}
21944
21945impl CompletionProvider for Entity<Project> {
21946    fn completions(
21947        &self,
21948        _excerpt_id: ExcerptId,
21949        buffer: &Entity<Buffer>,
21950        buffer_position: text::Anchor,
21951        options: CompletionContext,
21952        _window: &mut Window,
21953        cx: &mut Context<Editor>,
21954    ) -> Task<Result<Vec<CompletionResponse>>> {
21955        self.update(cx, |project, cx| {
21956            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21957            let project_completions = project.completions(buffer, buffer_position, options, cx);
21958            cx.background_spawn(async move {
21959                let mut responses = project_completions.await?;
21960                let snippets = snippets.await?;
21961                if !snippets.completions.is_empty() {
21962                    responses.push(snippets);
21963                }
21964                Ok(responses)
21965            })
21966        })
21967    }
21968
21969    fn resolve_completions(
21970        &self,
21971        buffer: Entity<Buffer>,
21972        completion_indices: Vec<usize>,
21973        completions: Rc<RefCell<Box<[Completion]>>>,
21974        cx: &mut Context<Editor>,
21975    ) -> Task<Result<bool>> {
21976        self.update(cx, |project, cx| {
21977            project.lsp_store().update(cx, |lsp_store, cx| {
21978                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21979            })
21980        })
21981    }
21982
21983    fn apply_additional_edits_for_completion(
21984        &self,
21985        buffer: Entity<Buffer>,
21986        completions: Rc<RefCell<Box<[Completion]>>>,
21987        completion_index: usize,
21988        push_to_history: bool,
21989        cx: &mut Context<Editor>,
21990    ) -> Task<Result<Option<language::Transaction>>> {
21991        self.update(cx, |project, cx| {
21992            project.lsp_store().update(cx, |lsp_store, cx| {
21993                lsp_store.apply_additional_edits_for_completion(
21994                    buffer,
21995                    completions,
21996                    completion_index,
21997                    push_to_history,
21998                    cx,
21999                )
22000            })
22001        })
22002    }
22003
22004    fn is_completion_trigger(
22005        &self,
22006        buffer: &Entity<Buffer>,
22007        position: language::Anchor,
22008        text: &str,
22009        trigger_in_words: bool,
22010        menu_is_open: bool,
22011        cx: &mut Context<Editor>,
22012    ) -> bool {
22013        let mut chars = text.chars();
22014        let char = if let Some(char) = chars.next() {
22015            char
22016        } else {
22017            return false;
22018        };
22019        if chars.next().is_some() {
22020            return false;
22021        }
22022
22023        let buffer = buffer.read(cx);
22024        let snapshot = buffer.snapshot();
22025        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22026            return false;
22027        }
22028        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22029        if trigger_in_words && classifier.is_word(char) {
22030            return true;
22031        }
22032
22033        buffer.completion_triggers().contains(text)
22034    }
22035}
22036
22037impl SemanticsProvider for Entity<Project> {
22038    fn hover(
22039        &self,
22040        buffer: &Entity<Buffer>,
22041        position: text::Anchor,
22042        cx: &mut App,
22043    ) -> Option<Task<Vec<project::Hover>>> {
22044        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22045    }
22046
22047    fn document_highlights(
22048        &self,
22049        buffer: &Entity<Buffer>,
22050        position: text::Anchor,
22051        cx: &mut App,
22052    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22053        Some(self.update(cx, |project, cx| {
22054            project.document_highlights(buffer, position, cx)
22055        }))
22056    }
22057
22058    fn definitions(
22059        &self,
22060        buffer: &Entity<Buffer>,
22061        position: text::Anchor,
22062        kind: GotoDefinitionKind,
22063        cx: &mut App,
22064    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22065        Some(self.update(cx, |project, cx| match kind {
22066            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22067            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22068            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22069            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22070        }))
22071    }
22072
22073    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22074        // TODO: make this work for remote projects
22075        self.update(cx, |project, cx| {
22076            if project
22077                .active_debug_session(cx)
22078                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22079            {
22080                return true;
22081            }
22082
22083            buffer.update(cx, |buffer, cx| {
22084                project.any_language_server_supports_inlay_hints(buffer, cx)
22085            })
22086        })
22087    }
22088
22089    fn inline_values(
22090        &self,
22091        buffer_handle: Entity<Buffer>,
22092        range: Range<text::Anchor>,
22093        cx: &mut App,
22094    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22095        self.update(cx, |project, cx| {
22096            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22097
22098            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22099        })
22100    }
22101
22102    fn inlay_hints(
22103        &self,
22104        buffer_handle: Entity<Buffer>,
22105        range: Range<text::Anchor>,
22106        cx: &mut App,
22107    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22108        Some(self.update(cx, |project, cx| {
22109            project.inlay_hints(buffer_handle, range, cx)
22110        }))
22111    }
22112
22113    fn resolve_inlay_hint(
22114        &self,
22115        hint: InlayHint,
22116        buffer_handle: Entity<Buffer>,
22117        server_id: LanguageServerId,
22118        cx: &mut App,
22119    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22120        Some(self.update(cx, |project, cx| {
22121            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22122        }))
22123    }
22124
22125    fn range_for_rename(
22126        &self,
22127        buffer: &Entity<Buffer>,
22128        position: text::Anchor,
22129        cx: &mut App,
22130    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22131        Some(self.update(cx, |project, cx| {
22132            let buffer = buffer.clone();
22133            let task = project.prepare_rename(buffer.clone(), position, cx);
22134            cx.spawn(async move |_, cx| {
22135                Ok(match task.await? {
22136                    PrepareRenameResponse::Success(range) => Some(range),
22137                    PrepareRenameResponse::InvalidPosition => None,
22138                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22139                        // Fallback on using TreeSitter info to determine identifier range
22140                        buffer.read_with(cx, |buffer, _| {
22141                            let snapshot = buffer.snapshot();
22142                            let (range, kind) = snapshot.surrounding_word(position);
22143                            if kind != Some(CharKind::Word) {
22144                                return None;
22145                            }
22146                            Some(
22147                                snapshot.anchor_before(range.start)
22148                                    ..snapshot.anchor_after(range.end),
22149                            )
22150                        })?
22151                    }
22152                })
22153            })
22154        }))
22155    }
22156
22157    fn perform_rename(
22158        &self,
22159        buffer: &Entity<Buffer>,
22160        position: text::Anchor,
22161        new_name: String,
22162        cx: &mut App,
22163    ) -> Option<Task<Result<ProjectTransaction>>> {
22164        Some(self.update(cx, |project, cx| {
22165            project.perform_rename(buffer.clone(), position, new_name, cx)
22166        }))
22167    }
22168}
22169
22170fn inlay_hint_settings(
22171    location: Anchor,
22172    snapshot: &MultiBufferSnapshot,
22173    cx: &mut Context<Editor>,
22174) -> InlayHintSettings {
22175    let file = snapshot.file_at(location);
22176    let language = snapshot.language_at(location).map(|l| l.name());
22177    language_settings(language, file, cx).inlay_hints
22178}
22179
22180fn consume_contiguous_rows(
22181    contiguous_row_selections: &mut Vec<Selection<Point>>,
22182    selection: &Selection<Point>,
22183    display_map: &DisplaySnapshot,
22184    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22185) -> (MultiBufferRow, MultiBufferRow) {
22186    contiguous_row_selections.push(selection.clone());
22187    let start_row = MultiBufferRow(selection.start.row);
22188    let mut end_row = ending_row(selection, display_map);
22189
22190    while let Some(next_selection) = selections.peek() {
22191        if next_selection.start.row <= end_row.0 {
22192            end_row = ending_row(next_selection, display_map);
22193            contiguous_row_selections.push(selections.next().unwrap().clone());
22194        } else {
22195            break;
22196        }
22197    }
22198    (start_row, end_row)
22199}
22200
22201fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22202    if next_selection.end.column > 0 || next_selection.is_empty() {
22203        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22204    } else {
22205        MultiBufferRow(next_selection.end.row)
22206    }
22207}
22208
22209impl EditorSnapshot {
22210    pub fn remote_selections_in_range<'a>(
22211        &'a self,
22212        range: &'a Range<Anchor>,
22213        collaboration_hub: &dyn CollaborationHub,
22214        cx: &'a App,
22215    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22216        let participant_names = collaboration_hub.user_names(cx);
22217        let participant_indices = collaboration_hub.user_participant_indices(cx);
22218        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22219        let collaborators_by_replica_id = collaborators_by_peer_id
22220            .values()
22221            .map(|collaborator| (collaborator.replica_id, collaborator))
22222            .collect::<HashMap<_, _>>();
22223        self.buffer_snapshot
22224            .selections_in_range(range, false)
22225            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22226                if replica_id == AGENT_REPLICA_ID {
22227                    Some(RemoteSelection {
22228                        replica_id,
22229                        selection,
22230                        cursor_shape,
22231                        line_mode,
22232                        collaborator_id: CollaboratorId::Agent,
22233                        user_name: Some("Agent".into()),
22234                        color: cx.theme().players().agent(),
22235                    })
22236                } else {
22237                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22238                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22239                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22240                    Some(RemoteSelection {
22241                        replica_id,
22242                        selection,
22243                        cursor_shape,
22244                        line_mode,
22245                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22246                        user_name,
22247                        color: if let Some(index) = participant_index {
22248                            cx.theme().players().color_for_participant(index.0)
22249                        } else {
22250                            cx.theme().players().absent()
22251                        },
22252                    })
22253                }
22254            })
22255    }
22256
22257    pub fn hunks_for_ranges(
22258        &self,
22259        ranges: impl IntoIterator<Item = Range<Point>>,
22260    ) -> Vec<MultiBufferDiffHunk> {
22261        let mut hunks = Vec::new();
22262        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22263            HashMap::default();
22264        for query_range in ranges {
22265            let query_rows =
22266                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22267            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22268                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22269            ) {
22270                // Include deleted hunks that are adjacent to the query range, because
22271                // otherwise they would be missed.
22272                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22273                if hunk.status().is_deleted() {
22274                    intersects_range |= hunk.row_range.start == query_rows.end;
22275                    intersects_range |= hunk.row_range.end == query_rows.start;
22276                }
22277                if intersects_range {
22278                    if !processed_buffer_rows
22279                        .entry(hunk.buffer_id)
22280                        .or_default()
22281                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22282                    {
22283                        continue;
22284                    }
22285                    hunks.push(hunk);
22286                }
22287            }
22288        }
22289
22290        hunks
22291    }
22292
22293    fn display_diff_hunks_for_rows<'a>(
22294        &'a self,
22295        display_rows: Range<DisplayRow>,
22296        folded_buffers: &'a HashSet<BufferId>,
22297    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22298        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22299        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22300
22301        self.buffer_snapshot
22302            .diff_hunks_in_range(buffer_start..buffer_end)
22303            .filter_map(|hunk| {
22304                if folded_buffers.contains(&hunk.buffer_id) {
22305                    return None;
22306                }
22307
22308                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22309                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22310
22311                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22312                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22313
22314                let display_hunk = if hunk_display_start.column() != 0 {
22315                    DisplayDiffHunk::Folded {
22316                        display_row: hunk_display_start.row(),
22317                    }
22318                } else {
22319                    let mut end_row = hunk_display_end.row();
22320                    if hunk_display_end.column() > 0 {
22321                        end_row.0 += 1;
22322                    }
22323                    let is_created_file = hunk.is_created_file();
22324                    DisplayDiffHunk::Unfolded {
22325                        status: hunk.status(),
22326                        diff_base_byte_range: hunk.diff_base_byte_range,
22327                        display_row_range: hunk_display_start.row()..end_row,
22328                        multi_buffer_range: Anchor::range_in_buffer(
22329                            hunk.excerpt_id,
22330                            hunk.buffer_id,
22331                            hunk.buffer_range,
22332                        ),
22333                        is_created_file,
22334                    }
22335                };
22336
22337                Some(display_hunk)
22338            })
22339    }
22340
22341    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22342        self.display_snapshot.buffer_snapshot.language_at(position)
22343    }
22344
22345    pub fn is_focused(&self) -> bool {
22346        self.is_focused
22347    }
22348
22349    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22350        self.placeholder_text.as_ref()
22351    }
22352
22353    pub fn scroll_position(&self) -> gpui::Point<f32> {
22354        self.scroll_anchor.scroll_position(&self.display_snapshot)
22355    }
22356
22357    fn gutter_dimensions(
22358        &self,
22359        font_id: FontId,
22360        font_size: Pixels,
22361        max_line_number_width: Pixels,
22362        cx: &App,
22363    ) -> Option<GutterDimensions> {
22364        if !self.show_gutter {
22365            return None;
22366        }
22367
22368        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22369        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22370
22371        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22372            matches!(
22373                ProjectSettings::get_global(cx).git.git_gutter,
22374                Some(GitGutterSetting::TrackedFiles)
22375            )
22376        });
22377        let gutter_settings = EditorSettings::get_global(cx).gutter;
22378        let show_line_numbers = self
22379            .show_line_numbers
22380            .unwrap_or(gutter_settings.line_numbers);
22381        let line_gutter_width = if show_line_numbers {
22382            // Avoid flicker-like gutter resizes when the line number gains another digit by
22383            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22384            let min_width_for_number_on_gutter =
22385                ch_advance * gutter_settings.min_line_number_digits as f32;
22386            max_line_number_width.max(min_width_for_number_on_gutter)
22387        } else {
22388            0.0.into()
22389        };
22390
22391        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22392        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22393
22394        let git_blame_entries_width =
22395            self.git_blame_gutter_max_author_length
22396                .map(|max_author_length| {
22397                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22398                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22399
22400                    /// The number of characters to dedicate to gaps and margins.
22401                    const SPACING_WIDTH: usize = 4;
22402
22403                    let max_char_count = max_author_length.min(renderer.max_author_length())
22404                        + ::git::SHORT_SHA_LENGTH
22405                        + MAX_RELATIVE_TIMESTAMP.len()
22406                        + SPACING_WIDTH;
22407
22408                    ch_advance * max_char_count
22409                });
22410
22411        let is_singleton = self.buffer_snapshot.is_singleton();
22412
22413        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22414        left_padding += if !is_singleton {
22415            ch_width * 4.0
22416        } else if show_runnables || show_breakpoints {
22417            ch_width * 3.0
22418        } else if show_git_gutter && show_line_numbers {
22419            ch_width * 2.0
22420        } else if show_git_gutter || show_line_numbers {
22421            ch_width
22422        } else {
22423            px(0.)
22424        };
22425
22426        let shows_folds = is_singleton && gutter_settings.folds;
22427
22428        let right_padding = if shows_folds && show_line_numbers {
22429            ch_width * 4.0
22430        } else if shows_folds || (!is_singleton && show_line_numbers) {
22431            ch_width * 3.0
22432        } else if show_line_numbers {
22433            ch_width
22434        } else {
22435            px(0.)
22436        };
22437
22438        Some(GutterDimensions {
22439            left_padding,
22440            right_padding,
22441            width: line_gutter_width + left_padding + right_padding,
22442            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22443            git_blame_entries_width,
22444        })
22445    }
22446
22447    pub fn render_crease_toggle(
22448        &self,
22449        buffer_row: MultiBufferRow,
22450        row_contains_cursor: bool,
22451        editor: Entity<Editor>,
22452        window: &mut Window,
22453        cx: &mut App,
22454    ) -> Option<AnyElement> {
22455        let folded = self.is_line_folded(buffer_row);
22456        let mut is_foldable = false;
22457
22458        if let Some(crease) = self
22459            .crease_snapshot
22460            .query_row(buffer_row, &self.buffer_snapshot)
22461        {
22462            is_foldable = true;
22463            match crease {
22464                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22465                    if let Some(render_toggle) = render_toggle {
22466                        let toggle_callback =
22467                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22468                                if folded {
22469                                    editor.update(cx, |editor, cx| {
22470                                        editor.fold_at(buffer_row, window, cx)
22471                                    });
22472                                } else {
22473                                    editor.update(cx, |editor, cx| {
22474                                        editor.unfold_at(buffer_row, window, cx)
22475                                    });
22476                                }
22477                            });
22478                        return Some((render_toggle)(
22479                            buffer_row,
22480                            folded,
22481                            toggle_callback,
22482                            window,
22483                            cx,
22484                        ));
22485                    }
22486                }
22487            }
22488        }
22489
22490        is_foldable |= self.starts_indent(buffer_row);
22491
22492        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22493            Some(
22494                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22495                    .toggle_state(folded)
22496                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22497                        if folded {
22498                            this.unfold_at(buffer_row, window, cx);
22499                        } else {
22500                            this.fold_at(buffer_row, window, cx);
22501                        }
22502                    }))
22503                    .into_any_element(),
22504            )
22505        } else {
22506            None
22507        }
22508    }
22509
22510    pub fn render_crease_trailer(
22511        &self,
22512        buffer_row: MultiBufferRow,
22513        window: &mut Window,
22514        cx: &mut App,
22515    ) -> Option<AnyElement> {
22516        let folded = self.is_line_folded(buffer_row);
22517        if let Crease::Inline { render_trailer, .. } = self
22518            .crease_snapshot
22519            .query_row(buffer_row, &self.buffer_snapshot)?
22520        {
22521            let render_trailer = render_trailer.as_ref()?;
22522            Some(render_trailer(buffer_row, folded, window, cx))
22523        } else {
22524            None
22525        }
22526    }
22527}
22528
22529impl Deref for EditorSnapshot {
22530    type Target = DisplaySnapshot;
22531
22532    fn deref(&self) -> &Self::Target {
22533        &self.display_snapshot
22534    }
22535}
22536
22537#[derive(Clone, Debug, PartialEq, Eq)]
22538pub enum EditorEvent {
22539    InputIgnored {
22540        text: Arc<str>,
22541    },
22542    InputHandled {
22543        utf16_range_to_replace: Option<Range<isize>>,
22544        text: Arc<str>,
22545    },
22546    ExcerptsAdded {
22547        buffer: Entity<Buffer>,
22548        predecessor: ExcerptId,
22549        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22550    },
22551    ExcerptsRemoved {
22552        ids: Vec<ExcerptId>,
22553        removed_buffer_ids: Vec<BufferId>,
22554    },
22555    BufferFoldToggled {
22556        ids: Vec<ExcerptId>,
22557        folded: bool,
22558    },
22559    ExcerptsEdited {
22560        ids: Vec<ExcerptId>,
22561    },
22562    ExcerptsExpanded {
22563        ids: Vec<ExcerptId>,
22564    },
22565    BufferEdited,
22566    Edited {
22567        transaction_id: clock::Lamport,
22568    },
22569    Reparsed(BufferId),
22570    Focused,
22571    FocusedIn,
22572    Blurred,
22573    DirtyChanged,
22574    Saved,
22575    TitleChanged,
22576    DiffBaseChanged,
22577    SelectionsChanged {
22578        local: bool,
22579    },
22580    ScrollPositionChanged {
22581        local: bool,
22582        autoscroll: bool,
22583    },
22584    Closed,
22585    TransactionUndone {
22586        transaction_id: clock::Lamport,
22587    },
22588    TransactionBegun {
22589        transaction_id: clock::Lamport,
22590    },
22591    Reloaded,
22592    CursorShapeChanged,
22593    PushedToNavHistory {
22594        anchor: Anchor,
22595        is_deactivate: bool,
22596    },
22597}
22598
22599impl EventEmitter<EditorEvent> for Editor {}
22600
22601impl Focusable for Editor {
22602    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22603        self.focus_handle.clone()
22604    }
22605}
22606
22607impl Render for Editor {
22608    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22609        let settings = ThemeSettings::get_global(cx);
22610
22611        let mut text_style = match self.mode {
22612            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22613                color: cx.theme().colors().editor_foreground,
22614                font_family: settings.ui_font.family.clone(),
22615                font_features: settings.ui_font.features.clone(),
22616                font_fallbacks: settings.ui_font.fallbacks.clone(),
22617                font_size: rems(0.875).into(),
22618                font_weight: settings.ui_font.weight,
22619                line_height: relative(settings.buffer_line_height.value()),
22620                ..Default::default()
22621            },
22622            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22623                color: cx.theme().colors().editor_foreground,
22624                font_family: settings.buffer_font.family.clone(),
22625                font_features: settings.buffer_font.features.clone(),
22626                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22627                font_size: settings.buffer_font_size(cx).into(),
22628                font_weight: settings.buffer_font.weight,
22629                line_height: relative(settings.buffer_line_height.value()),
22630                ..Default::default()
22631            },
22632        };
22633        if let Some(text_style_refinement) = &self.text_style_refinement {
22634            text_style.refine(text_style_refinement)
22635        }
22636
22637        let background = match self.mode {
22638            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22639            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22640            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22641            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22642        };
22643
22644        EditorElement::new(
22645            &cx.entity(),
22646            EditorStyle {
22647                background,
22648                border: cx.theme().colors().border,
22649                local_player: cx.theme().players().local(),
22650                text: text_style,
22651                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22652                syntax: cx.theme().syntax().clone(),
22653                status: cx.theme().status().clone(),
22654                inlay_hints_style: make_inlay_hints_style(cx),
22655                inline_completion_styles: make_suggestion_styles(cx),
22656                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22657                show_underlines: self.diagnostics_enabled(),
22658            },
22659        )
22660    }
22661}
22662
22663impl EntityInputHandler for Editor {
22664    fn text_for_range(
22665        &mut self,
22666        range_utf16: Range<usize>,
22667        adjusted_range: &mut Option<Range<usize>>,
22668        _: &mut Window,
22669        cx: &mut Context<Self>,
22670    ) -> Option<String> {
22671        let snapshot = self.buffer.read(cx).read(cx);
22672        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22673        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22674        if (start.0..end.0) != range_utf16 {
22675            adjusted_range.replace(start.0..end.0);
22676        }
22677        Some(snapshot.text_for_range(start..end).collect())
22678    }
22679
22680    fn selected_text_range(
22681        &mut self,
22682        ignore_disabled_input: bool,
22683        _: &mut Window,
22684        cx: &mut Context<Self>,
22685    ) -> Option<UTF16Selection> {
22686        // Prevent the IME menu from appearing when holding down an alphabetic key
22687        // while input is disabled.
22688        if !ignore_disabled_input && !self.input_enabled {
22689            return None;
22690        }
22691
22692        let selection = self.selections.newest::<OffsetUtf16>(cx);
22693        let range = selection.range();
22694
22695        Some(UTF16Selection {
22696            range: range.start.0..range.end.0,
22697            reversed: selection.reversed,
22698        })
22699    }
22700
22701    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22702        let snapshot = self.buffer.read(cx).read(cx);
22703        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22704        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22705    }
22706
22707    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22708        self.clear_highlights::<InputComposition>(cx);
22709        self.ime_transaction.take();
22710    }
22711
22712    fn replace_text_in_range(
22713        &mut self,
22714        range_utf16: Option<Range<usize>>,
22715        text: &str,
22716        window: &mut Window,
22717        cx: &mut Context<Self>,
22718    ) {
22719        if !self.input_enabled {
22720            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22721            return;
22722        }
22723
22724        self.transact(window, cx, |this, window, cx| {
22725            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22726                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22727                Some(this.selection_replacement_ranges(range_utf16, cx))
22728            } else {
22729                this.marked_text_ranges(cx)
22730            };
22731
22732            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22733                let newest_selection_id = this.selections.newest_anchor().id;
22734                this.selections
22735                    .all::<OffsetUtf16>(cx)
22736                    .iter()
22737                    .zip(ranges_to_replace.iter())
22738                    .find_map(|(selection, range)| {
22739                        if selection.id == newest_selection_id {
22740                            Some(
22741                                (range.start.0 as isize - selection.head().0 as isize)
22742                                    ..(range.end.0 as isize - selection.head().0 as isize),
22743                            )
22744                        } else {
22745                            None
22746                        }
22747                    })
22748            });
22749
22750            cx.emit(EditorEvent::InputHandled {
22751                utf16_range_to_replace: range_to_replace,
22752                text: text.into(),
22753            });
22754
22755            if let Some(new_selected_ranges) = new_selected_ranges {
22756                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22757                    selections.select_ranges(new_selected_ranges)
22758                });
22759                this.backspace(&Default::default(), window, cx);
22760            }
22761
22762            this.handle_input(text, window, cx);
22763        });
22764
22765        if let Some(transaction) = self.ime_transaction {
22766            self.buffer.update(cx, |buffer, cx| {
22767                buffer.group_until_transaction(transaction, cx);
22768            });
22769        }
22770
22771        self.unmark_text(window, cx);
22772    }
22773
22774    fn replace_and_mark_text_in_range(
22775        &mut self,
22776        range_utf16: Option<Range<usize>>,
22777        text: &str,
22778        new_selected_range_utf16: Option<Range<usize>>,
22779        window: &mut Window,
22780        cx: &mut Context<Self>,
22781    ) {
22782        if !self.input_enabled {
22783            return;
22784        }
22785
22786        let transaction = self.transact(window, cx, |this, window, cx| {
22787            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22788                let snapshot = this.buffer.read(cx).read(cx);
22789                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22790                    for marked_range in &mut marked_ranges {
22791                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22792                        marked_range.start.0 += relative_range_utf16.start;
22793                        marked_range.start =
22794                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22795                        marked_range.end =
22796                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22797                    }
22798                }
22799                Some(marked_ranges)
22800            } else if let Some(range_utf16) = range_utf16 {
22801                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22802                Some(this.selection_replacement_ranges(range_utf16, cx))
22803            } else {
22804                None
22805            };
22806
22807            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22808                let newest_selection_id = this.selections.newest_anchor().id;
22809                this.selections
22810                    .all::<OffsetUtf16>(cx)
22811                    .iter()
22812                    .zip(ranges_to_replace.iter())
22813                    .find_map(|(selection, range)| {
22814                        if selection.id == newest_selection_id {
22815                            Some(
22816                                (range.start.0 as isize - selection.head().0 as isize)
22817                                    ..(range.end.0 as isize - selection.head().0 as isize),
22818                            )
22819                        } else {
22820                            None
22821                        }
22822                    })
22823            });
22824
22825            cx.emit(EditorEvent::InputHandled {
22826                utf16_range_to_replace: range_to_replace,
22827                text: text.into(),
22828            });
22829
22830            if let Some(ranges) = ranges_to_replace {
22831                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22832                    s.select_ranges(ranges)
22833                });
22834            }
22835
22836            let marked_ranges = {
22837                let snapshot = this.buffer.read(cx).read(cx);
22838                this.selections
22839                    .disjoint_anchors()
22840                    .iter()
22841                    .map(|selection| {
22842                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22843                    })
22844                    .collect::<Vec<_>>()
22845            };
22846
22847            if text.is_empty() {
22848                this.unmark_text(window, cx);
22849            } else {
22850                this.highlight_text::<InputComposition>(
22851                    marked_ranges.clone(),
22852                    HighlightStyle {
22853                        underline: Some(UnderlineStyle {
22854                            thickness: px(1.),
22855                            color: None,
22856                            wavy: false,
22857                        }),
22858                        ..Default::default()
22859                    },
22860                    cx,
22861                );
22862            }
22863
22864            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22865            let use_autoclose = this.use_autoclose;
22866            let use_auto_surround = this.use_auto_surround;
22867            this.set_use_autoclose(false);
22868            this.set_use_auto_surround(false);
22869            this.handle_input(text, window, cx);
22870            this.set_use_autoclose(use_autoclose);
22871            this.set_use_auto_surround(use_auto_surround);
22872
22873            if let Some(new_selected_range) = new_selected_range_utf16 {
22874                let snapshot = this.buffer.read(cx).read(cx);
22875                let new_selected_ranges = marked_ranges
22876                    .into_iter()
22877                    .map(|marked_range| {
22878                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22879                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22880                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22881                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22882                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22883                    })
22884                    .collect::<Vec<_>>();
22885
22886                drop(snapshot);
22887                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22888                    selections.select_ranges(new_selected_ranges)
22889                });
22890            }
22891        });
22892
22893        self.ime_transaction = self.ime_transaction.or(transaction);
22894        if let Some(transaction) = self.ime_transaction {
22895            self.buffer.update(cx, |buffer, cx| {
22896                buffer.group_until_transaction(transaction, cx);
22897            });
22898        }
22899
22900        if self.text_highlights::<InputComposition>(cx).is_none() {
22901            self.ime_transaction.take();
22902        }
22903    }
22904
22905    fn bounds_for_range(
22906        &mut self,
22907        range_utf16: Range<usize>,
22908        element_bounds: gpui::Bounds<Pixels>,
22909        window: &mut Window,
22910        cx: &mut Context<Self>,
22911    ) -> Option<gpui::Bounds<Pixels>> {
22912        let text_layout_details = self.text_layout_details(window);
22913        let CharacterDimensions {
22914            em_width,
22915            em_advance,
22916            line_height,
22917        } = self.character_dimensions(window);
22918
22919        let snapshot = self.snapshot(window, cx);
22920        let scroll_position = snapshot.scroll_position();
22921        let scroll_left = scroll_position.x * em_advance;
22922
22923        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22924        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22925            + self.gutter_dimensions.full_width();
22926        let y = line_height * (start.row().as_f32() - scroll_position.y);
22927
22928        Some(Bounds {
22929            origin: element_bounds.origin + point(x, y),
22930            size: size(em_width, line_height),
22931        })
22932    }
22933
22934    fn character_index_for_point(
22935        &mut self,
22936        point: gpui::Point<Pixels>,
22937        _window: &mut Window,
22938        _cx: &mut Context<Self>,
22939    ) -> Option<usize> {
22940        let position_map = self.last_position_map.as_ref()?;
22941        if !position_map.text_hitbox.contains(&point) {
22942            return None;
22943        }
22944        let display_point = position_map.point_for_position(point).previous_valid;
22945        let anchor = position_map
22946            .snapshot
22947            .display_point_to_anchor(display_point, Bias::Left);
22948        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22949        Some(utf16_offset.0)
22950    }
22951}
22952
22953trait SelectionExt {
22954    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22955    fn spanned_rows(
22956        &self,
22957        include_end_if_at_line_start: bool,
22958        map: &DisplaySnapshot,
22959    ) -> Range<MultiBufferRow>;
22960}
22961
22962impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22963    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22964        let start = self
22965            .start
22966            .to_point(&map.buffer_snapshot)
22967            .to_display_point(map);
22968        let end = self
22969            .end
22970            .to_point(&map.buffer_snapshot)
22971            .to_display_point(map);
22972        if self.reversed {
22973            end..start
22974        } else {
22975            start..end
22976        }
22977    }
22978
22979    fn spanned_rows(
22980        &self,
22981        include_end_if_at_line_start: bool,
22982        map: &DisplaySnapshot,
22983    ) -> Range<MultiBufferRow> {
22984        let start = self.start.to_point(&map.buffer_snapshot);
22985        let mut end = self.end.to_point(&map.buffer_snapshot);
22986        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22987            end.row -= 1;
22988        }
22989
22990        let buffer_start = map.prev_line_boundary(start).0;
22991        let buffer_end = map.next_line_boundary(end).0;
22992        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22993    }
22994}
22995
22996impl<T: InvalidationRegion> InvalidationStack<T> {
22997    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22998    where
22999        S: Clone + ToOffset,
23000    {
23001        while let Some(region) = self.last() {
23002            let all_selections_inside_invalidation_ranges =
23003                if selections.len() == region.ranges().len() {
23004                    selections
23005                        .iter()
23006                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23007                        .all(|(selection, invalidation_range)| {
23008                            let head = selection.head().to_offset(buffer);
23009                            invalidation_range.start <= head && invalidation_range.end >= head
23010                        })
23011                } else {
23012                    false
23013                };
23014
23015            if all_selections_inside_invalidation_ranges {
23016                break;
23017            } else {
23018                self.pop();
23019            }
23020        }
23021    }
23022}
23023
23024impl<T> Default for InvalidationStack<T> {
23025    fn default() -> Self {
23026        Self(Default::default())
23027    }
23028}
23029
23030impl<T> Deref for InvalidationStack<T> {
23031    type Target = Vec<T>;
23032
23033    fn deref(&self) -> &Self::Target {
23034        &self.0
23035    }
23036}
23037
23038impl<T> DerefMut for InvalidationStack<T> {
23039    fn deref_mut(&mut self) -> &mut Self::Target {
23040        &mut self.0
23041    }
23042}
23043
23044impl InvalidationRegion for SnippetState {
23045    fn ranges(&self) -> &[Range<Anchor>] {
23046        &self.ranges[self.active_index]
23047    }
23048}
23049
23050fn inline_completion_edit_text(
23051    current_snapshot: &BufferSnapshot,
23052    edits: &[(Range<Anchor>, String)],
23053    edit_preview: &EditPreview,
23054    include_deletions: bool,
23055    cx: &App,
23056) -> HighlightedText {
23057    let edits = edits
23058        .iter()
23059        .map(|(anchor, text)| {
23060            (
23061                anchor.start.text_anchor..anchor.end.text_anchor,
23062                text.clone(),
23063            )
23064        })
23065        .collect::<Vec<_>>();
23066
23067    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23068}
23069
23070pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23071    match severity {
23072        lsp::DiagnosticSeverity::ERROR => colors.error,
23073        lsp::DiagnosticSeverity::WARNING => colors.warning,
23074        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23075        lsp::DiagnosticSeverity::HINT => colors.info,
23076        _ => colors.ignored,
23077    }
23078}
23079
23080pub fn styled_runs_for_code_label<'a>(
23081    label: &'a CodeLabel,
23082    syntax_theme: &'a theme::SyntaxTheme,
23083) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23084    let fade_out = HighlightStyle {
23085        fade_out: Some(0.35),
23086        ..Default::default()
23087    };
23088
23089    let mut prev_end = label.filter_range.end;
23090    label
23091        .runs
23092        .iter()
23093        .enumerate()
23094        .flat_map(move |(ix, (range, highlight_id))| {
23095            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23096                style
23097            } else {
23098                return Default::default();
23099            };
23100            let mut muted_style = style;
23101            muted_style.highlight(fade_out);
23102
23103            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23104            if range.start >= label.filter_range.end {
23105                if range.start > prev_end {
23106                    runs.push((prev_end..range.start, fade_out));
23107                }
23108                runs.push((range.clone(), muted_style));
23109            } else if range.end <= label.filter_range.end {
23110                runs.push((range.clone(), style));
23111            } else {
23112                runs.push((range.start..label.filter_range.end, style));
23113                runs.push((label.filter_range.end..range.end, muted_style));
23114            }
23115            prev_end = cmp::max(prev_end, range.end);
23116
23117            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23118                runs.push((prev_end..label.text.len(), fade_out));
23119            }
23120
23121            runs
23122        })
23123}
23124
23125pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23126    let mut prev_index = 0;
23127    let mut prev_codepoint: Option<char> = None;
23128    text.char_indices()
23129        .chain([(text.len(), '\0')])
23130        .filter_map(move |(index, codepoint)| {
23131            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23132            let is_boundary = index == text.len()
23133                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23134                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23135            if is_boundary {
23136                let chunk = &text[prev_index..index];
23137                prev_index = index;
23138                Some(chunk)
23139            } else {
23140                None
23141            }
23142        })
23143}
23144
23145pub trait RangeToAnchorExt: Sized {
23146    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23147
23148    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23149        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23150        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23151    }
23152}
23153
23154impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23155    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23156        let start_offset = self.start.to_offset(snapshot);
23157        let end_offset = self.end.to_offset(snapshot);
23158        if start_offset == end_offset {
23159            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23160        } else {
23161            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23162        }
23163    }
23164}
23165
23166pub trait RowExt {
23167    fn as_f32(&self) -> f32;
23168
23169    fn next_row(&self) -> Self;
23170
23171    fn previous_row(&self) -> Self;
23172
23173    fn minus(&self, other: Self) -> u32;
23174}
23175
23176impl RowExt for DisplayRow {
23177    fn as_f32(&self) -> f32 {
23178        self.0 as f32
23179    }
23180
23181    fn next_row(&self) -> Self {
23182        Self(self.0 + 1)
23183    }
23184
23185    fn previous_row(&self) -> Self {
23186        Self(self.0.saturating_sub(1))
23187    }
23188
23189    fn minus(&self, other: Self) -> u32 {
23190        self.0 - other.0
23191    }
23192}
23193
23194impl RowExt for MultiBufferRow {
23195    fn as_f32(&self) -> f32 {
23196        self.0 as f32
23197    }
23198
23199    fn next_row(&self) -> Self {
23200        Self(self.0 + 1)
23201    }
23202
23203    fn previous_row(&self) -> Self {
23204        Self(self.0.saturating_sub(1))
23205    }
23206
23207    fn minus(&self, other: Self) -> u32 {
23208        self.0 - other.0
23209    }
23210}
23211
23212trait RowRangeExt {
23213    type Row;
23214
23215    fn len(&self) -> usize;
23216
23217    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23218}
23219
23220impl RowRangeExt for Range<MultiBufferRow> {
23221    type Row = MultiBufferRow;
23222
23223    fn len(&self) -> usize {
23224        (self.end.0 - self.start.0) as usize
23225    }
23226
23227    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23228        (self.start.0..self.end.0).map(MultiBufferRow)
23229    }
23230}
23231
23232impl RowRangeExt for Range<DisplayRow> {
23233    type Row = DisplayRow;
23234
23235    fn len(&self) -> usize {
23236        (self.end.0 - self.start.0) as usize
23237    }
23238
23239    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23240        (self.start.0..self.end.0).map(DisplayRow)
23241    }
23242}
23243
23244/// If select range has more than one line, we
23245/// just point the cursor to range.start.
23246fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23247    if range.start.row == range.end.row {
23248        range
23249    } else {
23250        range.start..range.start
23251    }
23252}
23253pub struct KillRing(ClipboardItem);
23254impl Global for KillRing {}
23255
23256const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23257
23258enum BreakpointPromptEditAction {
23259    Log,
23260    Condition,
23261    HitCondition,
23262}
23263
23264struct BreakpointPromptEditor {
23265    pub(crate) prompt: Entity<Editor>,
23266    editor: WeakEntity<Editor>,
23267    breakpoint_anchor: Anchor,
23268    breakpoint: Breakpoint,
23269    edit_action: BreakpointPromptEditAction,
23270    block_ids: HashSet<CustomBlockId>,
23271    editor_margins: Arc<Mutex<EditorMargins>>,
23272    _subscriptions: Vec<Subscription>,
23273}
23274
23275impl BreakpointPromptEditor {
23276    const MAX_LINES: u8 = 4;
23277
23278    fn new(
23279        editor: WeakEntity<Editor>,
23280        breakpoint_anchor: Anchor,
23281        breakpoint: Breakpoint,
23282        edit_action: BreakpointPromptEditAction,
23283        window: &mut Window,
23284        cx: &mut Context<Self>,
23285    ) -> Self {
23286        let base_text = match edit_action {
23287            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23288            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23289            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23290        }
23291        .map(|msg| msg.to_string())
23292        .unwrap_or_default();
23293
23294        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23295        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23296
23297        let prompt = cx.new(|cx| {
23298            let mut prompt = Editor::new(
23299                EditorMode::AutoHeight {
23300                    min_lines: 1,
23301                    max_lines: Some(Self::MAX_LINES as usize),
23302                },
23303                buffer,
23304                None,
23305                window,
23306                cx,
23307            );
23308            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23309            prompt.set_show_cursor_when_unfocused(false, cx);
23310            prompt.set_placeholder_text(
23311                match edit_action {
23312                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23313                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23314                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23315                },
23316                cx,
23317            );
23318
23319            prompt
23320        });
23321
23322        Self {
23323            prompt,
23324            editor,
23325            breakpoint_anchor,
23326            breakpoint,
23327            edit_action,
23328            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23329            block_ids: Default::default(),
23330            _subscriptions: vec![],
23331        }
23332    }
23333
23334    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23335        self.block_ids.extend(block_ids)
23336    }
23337
23338    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23339        if let Some(editor) = self.editor.upgrade() {
23340            let message = self
23341                .prompt
23342                .read(cx)
23343                .buffer
23344                .read(cx)
23345                .as_singleton()
23346                .expect("A multi buffer in breakpoint prompt isn't possible")
23347                .read(cx)
23348                .as_rope()
23349                .to_string();
23350
23351            editor.update(cx, |editor, cx| {
23352                editor.edit_breakpoint_at_anchor(
23353                    self.breakpoint_anchor,
23354                    self.breakpoint.clone(),
23355                    match self.edit_action {
23356                        BreakpointPromptEditAction::Log => {
23357                            BreakpointEditAction::EditLogMessage(message.into())
23358                        }
23359                        BreakpointPromptEditAction::Condition => {
23360                            BreakpointEditAction::EditCondition(message.into())
23361                        }
23362                        BreakpointPromptEditAction::HitCondition => {
23363                            BreakpointEditAction::EditHitCondition(message.into())
23364                        }
23365                    },
23366                    cx,
23367                );
23368
23369                editor.remove_blocks(self.block_ids.clone(), None, cx);
23370                cx.focus_self(window);
23371            });
23372        }
23373    }
23374
23375    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23376        self.editor
23377            .update(cx, |editor, cx| {
23378                editor.remove_blocks(self.block_ids.clone(), None, cx);
23379                window.focus(&editor.focus_handle);
23380            })
23381            .log_err();
23382    }
23383
23384    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23385        let settings = ThemeSettings::get_global(cx);
23386        let text_style = TextStyle {
23387            color: if self.prompt.read(cx).read_only(cx) {
23388                cx.theme().colors().text_disabled
23389            } else {
23390                cx.theme().colors().text
23391            },
23392            font_family: settings.buffer_font.family.clone(),
23393            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23394            font_size: settings.buffer_font_size(cx).into(),
23395            font_weight: settings.buffer_font.weight,
23396            line_height: relative(settings.buffer_line_height.value()),
23397            ..Default::default()
23398        };
23399        EditorElement::new(
23400            &self.prompt,
23401            EditorStyle {
23402                background: cx.theme().colors().editor_background,
23403                local_player: cx.theme().players().local(),
23404                text: text_style,
23405                ..Default::default()
23406            },
23407        )
23408    }
23409}
23410
23411impl Render for BreakpointPromptEditor {
23412    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23413        let editor_margins = *self.editor_margins.lock();
23414        let gutter_dimensions = editor_margins.gutter;
23415        h_flex()
23416            .key_context("Editor")
23417            .bg(cx.theme().colors().editor_background)
23418            .border_y_1()
23419            .border_color(cx.theme().status().info_border)
23420            .size_full()
23421            .py(window.line_height() / 2.5)
23422            .on_action(cx.listener(Self::confirm))
23423            .on_action(cx.listener(Self::cancel))
23424            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23425            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23426    }
23427}
23428
23429impl Focusable for BreakpointPromptEditor {
23430    fn focus_handle(&self, cx: &App) -> FocusHandle {
23431        self.prompt.focus_handle(cx)
23432    }
23433}
23434
23435fn all_edits_insertions_or_deletions(
23436    edits: &Vec<(Range<Anchor>, String)>,
23437    snapshot: &MultiBufferSnapshot,
23438) -> bool {
23439    let mut all_insertions = true;
23440    let mut all_deletions = true;
23441
23442    for (range, new_text) in edits.iter() {
23443        let range_is_empty = range.to_offset(&snapshot).is_empty();
23444        let text_is_empty = new_text.is_empty();
23445
23446        if range_is_empty != text_is_empty {
23447            if range_is_empty {
23448                all_deletions = false;
23449            } else {
23450                all_insertions = false;
23451            }
23452        } else {
23453            return false;
23454        }
23455
23456        if !all_insertions && !all_deletions {
23457            return false;
23458        }
23459    }
23460    all_insertions || all_deletions
23461}
23462
23463struct MissingEditPredictionKeybindingTooltip;
23464
23465impl Render for MissingEditPredictionKeybindingTooltip {
23466    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23467        ui::tooltip_container(window, cx, |container, _, cx| {
23468            container
23469                .flex_shrink_0()
23470                .max_w_80()
23471                .min_h(rems_from_px(124.))
23472                .justify_between()
23473                .child(
23474                    v_flex()
23475                        .flex_1()
23476                        .text_ui_sm(cx)
23477                        .child(Label::new("Conflict with Accept Keybinding"))
23478                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23479                )
23480                .child(
23481                    h_flex()
23482                        .pb_1()
23483                        .gap_1()
23484                        .items_end()
23485                        .w_full()
23486                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23487                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23488                        }))
23489                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23490                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23491                        })),
23492                )
23493        })
23494    }
23495}
23496
23497#[derive(Debug, Clone, Copy, PartialEq)]
23498pub struct LineHighlight {
23499    pub background: Background,
23500    pub border: Option<gpui::Hsla>,
23501    pub include_gutter: bool,
23502    pub type_id: Option<TypeId>,
23503}
23504
23505struct LineManipulationResult {
23506    pub new_text: String,
23507    pub line_count_before: usize,
23508    pub line_count_after: usize,
23509}
23510
23511fn render_diff_hunk_controls(
23512    row: u32,
23513    status: &DiffHunkStatus,
23514    hunk_range: Range<Anchor>,
23515    is_created_file: bool,
23516    line_height: Pixels,
23517    editor: &Entity<Editor>,
23518    _window: &mut Window,
23519    cx: &mut App,
23520) -> AnyElement {
23521    h_flex()
23522        .h(line_height)
23523        .mr_1()
23524        .gap_1()
23525        .px_0p5()
23526        .pb_1()
23527        .border_x_1()
23528        .border_b_1()
23529        .border_color(cx.theme().colors().border_variant)
23530        .rounded_b_lg()
23531        .bg(cx.theme().colors().editor_background)
23532        .gap_1()
23533        .block_mouse_except_scroll()
23534        .shadow_md()
23535        .child(if status.has_secondary_hunk() {
23536            Button::new(("stage", row as u64), "Stage")
23537                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23538                .tooltip({
23539                    let focus_handle = editor.focus_handle(cx);
23540                    move |window, cx| {
23541                        Tooltip::for_action_in(
23542                            "Stage Hunk",
23543                            &::git::ToggleStaged,
23544                            &focus_handle,
23545                            window,
23546                            cx,
23547                        )
23548                    }
23549                })
23550                .on_click({
23551                    let editor = editor.clone();
23552                    move |_event, _window, cx| {
23553                        editor.update(cx, |editor, cx| {
23554                            editor.stage_or_unstage_diff_hunks(
23555                                true,
23556                                vec![hunk_range.start..hunk_range.start],
23557                                cx,
23558                            );
23559                        });
23560                    }
23561                })
23562        } else {
23563            Button::new(("unstage", row as u64), "Unstage")
23564                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23565                .tooltip({
23566                    let focus_handle = editor.focus_handle(cx);
23567                    move |window, cx| {
23568                        Tooltip::for_action_in(
23569                            "Unstage Hunk",
23570                            &::git::ToggleStaged,
23571                            &focus_handle,
23572                            window,
23573                            cx,
23574                        )
23575                    }
23576                })
23577                .on_click({
23578                    let editor = editor.clone();
23579                    move |_event, _window, cx| {
23580                        editor.update(cx, |editor, cx| {
23581                            editor.stage_or_unstage_diff_hunks(
23582                                false,
23583                                vec![hunk_range.start..hunk_range.start],
23584                                cx,
23585                            );
23586                        });
23587                    }
23588                })
23589        })
23590        .child(
23591            Button::new(("restore", row as u64), "Restore")
23592                .tooltip({
23593                    let focus_handle = editor.focus_handle(cx);
23594                    move |window, cx| {
23595                        Tooltip::for_action_in(
23596                            "Restore Hunk",
23597                            &::git::Restore,
23598                            &focus_handle,
23599                            window,
23600                            cx,
23601                        )
23602                    }
23603                })
23604                .on_click({
23605                    let editor = editor.clone();
23606                    move |_event, window, cx| {
23607                        editor.update(cx, |editor, cx| {
23608                            let snapshot = editor.snapshot(window, cx);
23609                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23610                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23611                        });
23612                    }
23613                })
23614                .disabled(is_created_file),
23615        )
23616        .when(
23617            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23618            |el| {
23619                el.child(
23620                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23621                        .shape(IconButtonShape::Square)
23622                        .icon_size(IconSize::Small)
23623                        // .disabled(!has_multiple_hunks)
23624                        .tooltip({
23625                            let focus_handle = editor.focus_handle(cx);
23626                            move |window, cx| {
23627                                Tooltip::for_action_in(
23628                                    "Next Hunk",
23629                                    &GoToHunk,
23630                                    &focus_handle,
23631                                    window,
23632                                    cx,
23633                                )
23634                            }
23635                        })
23636                        .on_click({
23637                            let editor = editor.clone();
23638                            move |_event, window, cx| {
23639                                editor.update(cx, |editor, cx| {
23640                                    let snapshot = editor.snapshot(window, cx);
23641                                    let position =
23642                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23643                                    editor.go_to_hunk_before_or_after_position(
23644                                        &snapshot,
23645                                        position,
23646                                        Direction::Next,
23647                                        window,
23648                                        cx,
23649                                    );
23650                                    editor.expand_selected_diff_hunks(cx);
23651                                });
23652                            }
23653                        }),
23654                )
23655                .child(
23656                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23657                        .shape(IconButtonShape::Square)
23658                        .icon_size(IconSize::Small)
23659                        // .disabled(!has_multiple_hunks)
23660                        .tooltip({
23661                            let focus_handle = editor.focus_handle(cx);
23662                            move |window, cx| {
23663                                Tooltip::for_action_in(
23664                                    "Previous Hunk",
23665                                    &GoToPreviousHunk,
23666                                    &focus_handle,
23667                                    window,
23668                                    cx,
23669                                )
23670                            }
23671                        })
23672                        .on_click({
23673                            let editor = editor.clone();
23674                            move |_event, window, cx| {
23675                                editor.update(cx, |editor, cx| {
23676                                    let snapshot = editor.snapshot(window, cx);
23677                                    let point =
23678                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23679                                    editor.go_to_hunk_before_or_after_position(
23680                                        &snapshot,
23681                                        point,
23682                                        Direction::Prev,
23683                                        window,
23684                                        cx,
23685                                    );
23686                                    editor.expand_selected_diff_hunks(cx);
23687                                });
23688                            }
23689                        }),
23690                )
23691            },
23692        )
23693        .into_any_element()
23694}