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, DisableAiSettings, 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, BlockCommentConfig, BracketMatch, BracketPair, Buffer, Capability, CharKind,
  113    CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview,
  114    HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
  115    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};
  216use zed_actions;
  217
  218use crate::{
  219    code_context_menus::CompletionsMenuSource,
  220    hover_links::{find_url, find_url_from_range},
  221};
  222use crate::{
  223    editor_settings::MultiCursorModifier,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    DebuggerValue(usize),
  280    // LSP
  281    Hint(usize),
  282    Color(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::DebuggerValue(id) => *id,
  290            Self::Hint(id) => *id,
  291            Self::Color(id) => *id,
  292        }
  293    }
  294}
  295
  296pub enum ActiveDebugLine {}
  297pub enum DebugStackFrameLine {}
  298enum DocumentHighlightRead {}
  299enum DocumentHighlightWrite {}
  300enum InputComposition {}
  301pub enum PendingInput {}
  302enum SelectedTextHighlight {}
  303
  304pub enum ConflictsOuter {}
  305pub enum ConflictsOurs {}
  306pub enum ConflictsTheirs {}
  307pub enum ConflictsOursMarker {}
  308pub enum ConflictsTheirsMarker {}
  309
  310#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  311pub enum Navigated {
  312    Yes,
  313    No,
  314}
  315
  316impl Navigated {
  317    pub fn from_bool(yes: bool) -> Navigated {
  318        if yes { Navigated::Yes } else { Navigated::No }
  319    }
  320}
  321
  322#[derive(Debug, Clone, PartialEq, Eq)]
  323enum DisplayDiffHunk {
  324    Folded {
  325        display_row: DisplayRow,
  326    },
  327    Unfolded {
  328        is_created_file: bool,
  329        diff_base_byte_range: Range<usize>,
  330        display_row_range: Range<DisplayRow>,
  331        multi_buffer_range: Range<Anchor>,
  332        status: DiffHunkStatus,
  333    },
  334}
  335
  336pub enum HideMouseCursorOrigin {
  337    TypingAction,
  338    MovementAction,
  339}
  340
  341pub fn init_settings(cx: &mut App) {
  342    EditorSettings::register(cx);
  343}
  344
  345pub fn init(cx: &mut App) {
  346    init_settings(cx);
  347
  348    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  349
  350    workspace::register_project_item::<Editor>(cx);
  351    workspace::FollowableViewRegistry::register::<Editor>(cx);
  352    workspace::register_serializable_item::<Editor>(cx);
  353
  354    cx.observe_new(
  355        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  356            workspace.register_action(Editor::new_file);
  357            workspace.register_action(Editor::new_file_vertical);
  358            workspace.register_action(Editor::new_file_horizontal);
  359            workspace.register_action(Editor::cancel_language_server_work);
  360            workspace.register_action(Editor::toggle_focus);
  361        },
  362    )
  363    .detach();
  364
  365    cx.on_action(move |_: &workspace::NewFile, cx| {
  366        let app_state = workspace::AppState::global(cx);
  367        if let Some(app_state) = app_state.upgrade() {
  368            workspace::open_new(
  369                Default::default(),
  370                app_state,
  371                cx,
  372                |workspace, window, cx| {
  373                    Editor::new_file(workspace, &Default::default(), window, cx)
  374                },
  375            )
  376            .detach();
  377        }
  378    });
  379    cx.on_action(move |_: &workspace::NewWindow, cx| {
  380        let app_state = workspace::AppState::global(cx);
  381        if let Some(app_state) = app_state.upgrade() {
  382            workspace::open_new(
  383                Default::default(),
  384                app_state,
  385                cx,
  386                |workspace, window, cx| {
  387                    cx.activate(true);
  388                    Editor::new_file(workspace, &Default::default(), window, cx)
  389                },
  390            )
  391            .detach();
  392        }
  393    });
  394}
  395
  396pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  397    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  398}
  399
  400pub trait DiagnosticRenderer {
  401    fn render_group(
  402        &self,
  403        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  404        buffer_id: BufferId,
  405        snapshot: EditorSnapshot,
  406        editor: WeakEntity<Editor>,
  407        cx: &mut App,
  408    ) -> Vec<BlockProperties<Anchor>>;
  409
  410    fn render_hover(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        range: Range<Point>,
  414        buffer_id: BufferId,
  415        cx: &mut App,
  416    ) -> Option<Entity<markdown::Markdown>>;
  417
  418    fn open_link(
  419        &self,
  420        editor: &mut Editor,
  421        link: SharedString,
  422        window: &mut Window,
  423        cx: &mut Context<Editor>,
  424    );
  425}
  426
  427pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  428
  429impl GlobalDiagnosticRenderer {
  430    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  431        cx.try_global::<Self>().map(|g| g.0.clone())
  432    }
  433}
  434
  435impl gpui::Global for GlobalDiagnosticRenderer {}
  436pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  437    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  438}
  439
  440pub struct SearchWithinRange;
  441
  442trait InvalidationRegion {
  443    fn ranges(&self) -> &[Range<Anchor>];
  444}
  445
  446#[derive(Clone, Debug, PartialEq)]
  447pub enum SelectPhase {
  448    Begin {
  449        position: DisplayPoint,
  450        add: bool,
  451        click_count: usize,
  452    },
  453    BeginColumnar {
  454        position: DisplayPoint,
  455        reset: bool,
  456        mode: ColumnarMode,
  457        goal_column: u32,
  458    },
  459    Extend {
  460        position: DisplayPoint,
  461        click_count: usize,
  462    },
  463    Update {
  464        position: DisplayPoint,
  465        goal_column: u32,
  466        scroll_delta: gpui::Point<f32>,
  467    },
  468    End,
  469}
  470
  471#[derive(Clone, Debug, PartialEq)]
  472pub enum ColumnarMode {
  473    FromMouse,
  474    FromSelection,
  475}
  476
  477#[derive(Clone, Debug)]
  478pub enum SelectMode {
  479    Character,
  480    Word(Range<Anchor>),
  481    Line(Range<Anchor>),
  482    All,
  483}
  484
  485#[derive(Clone, PartialEq, Eq, Debug)]
  486pub enum EditorMode {
  487    SingleLine,
  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    keyboard_grace: bool,
  955}
  956
  957enum SelectionDragState {
  958    /// State when no drag related activity is detected.
  959    None,
  960    /// State when the mouse is down on a selection that is about to be dragged.
  961    ReadyToDrag {
  962        selection: Selection<Anchor>,
  963        click_position: gpui::Point<Pixels>,
  964        mouse_down_time: Instant,
  965    },
  966    /// State when the mouse is dragging the selection in the editor.
  967    Dragging {
  968        selection: Selection<Anchor>,
  969        drop_cursor: Selection<Anchor>,
  970        hide_drop_cursor: bool,
  971    },
  972}
  973
  974enum ColumnarSelectionState {
  975    FromMouse {
  976        selection_tail: Anchor,
  977        display_point: Option<DisplayPoint>,
  978    },
  979    FromSelection {
  980        selection_tail: Anchor,
  981    },
  982}
  983
  984/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  985/// a breakpoint on them.
  986#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  987struct PhantomBreakpointIndicator {
  988    display_row: DisplayRow,
  989    /// There's a small debounce between hovering over the line and showing the indicator.
  990    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  991    is_active: bool,
  992    collides_with_existing_breakpoint: bool,
  993}
  994
  995/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  996///
  997/// See the [module level documentation](self) for more information.
  998pub struct Editor {
  999    focus_handle: FocusHandle,
 1000    last_focused_descendant: Option<WeakFocusHandle>,
 1001    /// The text buffer being edited
 1002    buffer: Entity<MultiBuffer>,
 1003    /// Map of how text in the buffer should be displayed.
 1004    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1005    pub display_map: Entity<DisplayMap>,
 1006    pub selections: SelectionsCollection,
 1007    pub scroll_manager: ScrollManager,
 1008    /// When inline assist editors are linked, they all render cursors because
 1009    /// typing enters text into each of them, even the ones that aren't focused.
 1010    pub(crate) show_cursor_when_unfocused: bool,
 1011    columnar_selection_state: Option<ColumnarSelectionState>,
 1012    add_selections_state: Option<AddSelectionsState>,
 1013    select_next_state: Option<SelectNextState>,
 1014    select_prev_state: Option<SelectNextState>,
 1015    selection_history: SelectionHistory,
 1016    defer_selection_effects: bool,
 1017    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1018    autoclose_regions: Vec<AutocloseRegion>,
 1019    snippet_stack: InvalidationStack<SnippetState>,
 1020    select_syntax_node_history: SelectSyntaxNodeHistory,
 1021    ime_transaction: Option<TransactionId>,
 1022    pub diagnostics_max_severity: DiagnosticSeverity,
 1023    active_diagnostics: ActiveDiagnostic,
 1024    show_inline_diagnostics: bool,
 1025    inline_diagnostics_update: Task<()>,
 1026    inline_diagnostics_enabled: bool,
 1027    diagnostics_enabled: bool,
 1028    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1029    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1030    hard_wrap: Option<usize>,
 1031
 1032    // TODO: make this a access method
 1033    pub project: Option<Entity<Project>>,
 1034    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1035    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1036    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1037    blink_manager: Entity<BlinkManager>,
 1038    show_cursor_names: bool,
 1039    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1040    pub show_local_selections: bool,
 1041    mode: EditorMode,
 1042    show_breadcrumbs: bool,
 1043    show_gutter: bool,
 1044    show_scrollbars: ScrollbarAxes,
 1045    minimap_visibility: MinimapVisibility,
 1046    offset_content: bool,
 1047    disable_expand_excerpt_buttons: bool,
 1048    show_line_numbers: Option<bool>,
 1049    use_relative_line_numbers: Option<bool>,
 1050    show_git_diff_gutter: Option<bool>,
 1051    show_code_actions: Option<bool>,
 1052    show_runnables: Option<bool>,
 1053    show_breakpoints: Option<bool>,
 1054    show_wrap_guides: Option<bool>,
 1055    show_indent_guides: Option<bool>,
 1056    placeholder_text: Option<Arc<str>>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_inline_completion: Option<InlineCompletionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    inline_completions_hidden_for_vim_mode: bool,
 1104    show_inline_completions_override: Option<bool>,
 1105    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177}
 1178
 1179#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1180enum NextScrollCursorCenterTopBottom {
 1181    #[default]
 1182    Center,
 1183    Top,
 1184    Bottom,
 1185}
 1186
 1187impl NextScrollCursorCenterTopBottom {
 1188    fn next(&self) -> Self {
 1189        match self {
 1190            Self::Center => Self::Top,
 1191            Self::Top => Self::Bottom,
 1192            Self::Bottom => Self::Center,
 1193        }
 1194    }
 1195}
 1196
 1197#[derive(Clone)]
 1198pub struct EditorSnapshot {
 1199    pub mode: EditorMode,
 1200    show_gutter: bool,
 1201    show_line_numbers: Option<bool>,
 1202    show_git_diff_gutter: Option<bool>,
 1203    show_code_actions: Option<bool>,
 1204    show_runnables: Option<bool>,
 1205    show_breakpoints: Option<bool>,
 1206    git_blame_gutter_max_author_length: Option<usize>,
 1207    pub display_snapshot: DisplaySnapshot,
 1208    pub placeholder_text: Option<Arc<str>>,
 1209    is_focused: bool,
 1210    scroll_anchor: ScrollAnchor,
 1211    ongoing_scroll: OngoingScroll,
 1212    current_line_highlight: CurrentLineHighlight,
 1213    gutter_hovered: bool,
 1214}
 1215
 1216#[derive(Default, Debug, Clone, Copy)]
 1217pub struct GutterDimensions {
 1218    pub left_padding: Pixels,
 1219    pub right_padding: Pixels,
 1220    pub width: Pixels,
 1221    pub margin: Pixels,
 1222    pub git_blame_entries_width: Option<Pixels>,
 1223}
 1224
 1225impl GutterDimensions {
 1226    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1227        Self {
 1228            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1229            ..Default::default()
 1230        }
 1231    }
 1232
 1233    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1234        -cx.text_system().descent(font_id, font_size)
 1235    }
 1236    /// The full width of the space taken up by the gutter.
 1237    pub fn full_width(&self) -> Pixels {
 1238        self.margin + self.width
 1239    }
 1240
 1241    /// The width of the space reserved for the fold indicators,
 1242    /// use alongside 'justify_end' and `gutter_width` to
 1243    /// right align content with the line numbers
 1244    pub fn fold_area_width(&self) -> Pixels {
 1245        self.margin + self.right_padding
 1246    }
 1247}
 1248
 1249struct CharacterDimensions {
 1250    em_width: Pixels,
 1251    em_advance: Pixels,
 1252    line_height: Pixels,
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct RemoteSelection {
 1257    pub replica_id: ReplicaId,
 1258    pub selection: Selection<Anchor>,
 1259    pub cursor_shape: CursorShape,
 1260    pub collaborator_id: CollaboratorId,
 1261    pub line_mode: bool,
 1262    pub user_name: Option<SharedString>,
 1263    pub color: PlayerColor,
 1264}
 1265
 1266#[derive(Clone, Debug)]
 1267struct SelectionHistoryEntry {
 1268    selections: Arc<[Selection<Anchor>]>,
 1269    select_next_state: Option<SelectNextState>,
 1270    select_prev_state: Option<SelectNextState>,
 1271    add_selections_state: Option<AddSelectionsState>,
 1272}
 1273
 1274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1275enum SelectionHistoryMode {
 1276    Normal,
 1277    Undoing,
 1278    Redoing,
 1279    Skipping,
 1280}
 1281
 1282#[derive(Clone, PartialEq, Eq, Hash)]
 1283struct HoveredCursor {
 1284    replica_id: u16,
 1285    selection_id: usize,
 1286}
 1287
 1288impl Default for SelectionHistoryMode {
 1289    fn default() -> Self {
 1290        Self::Normal
 1291    }
 1292}
 1293
 1294#[derive(Debug)]
 1295/// SelectionEffects controls the side-effects of updating the selection.
 1296///
 1297/// The default behaviour does "what you mostly want":
 1298/// - it pushes to the nav history if the cursor moved by >10 lines
 1299/// - it re-triggers completion requests
 1300/// - it scrolls to fit
 1301///
 1302/// You might want to modify these behaviours. For example when doing a "jump"
 1303/// like go to definition, we always want to add to nav history; but when scrolling
 1304/// in vim mode we never do.
 1305///
 1306/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1307/// move.
 1308#[derive(Clone)]
 1309pub struct SelectionEffects {
 1310    nav_history: Option<bool>,
 1311    completions: bool,
 1312    scroll: Option<Autoscroll>,
 1313}
 1314
 1315impl Default for SelectionEffects {
 1316    fn default() -> Self {
 1317        Self {
 1318            nav_history: None,
 1319            completions: true,
 1320            scroll: Some(Autoscroll::fit()),
 1321        }
 1322    }
 1323}
 1324impl SelectionEffects {
 1325    pub fn scroll(scroll: Autoscroll) -> Self {
 1326        Self {
 1327            scroll: Some(scroll),
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn no_scroll() -> Self {
 1333        Self {
 1334            scroll: None,
 1335            ..Default::default()
 1336        }
 1337    }
 1338
 1339    pub fn completions(self, completions: bool) -> Self {
 1340        Self {
 1341            completions,
 1342            ..self
 1343        }
 1344    }
 1345
 1346    pub fn nav_history(self, nav_history: bool) -> Self {
 1347        Self {
 1348            nav_history: Some(nav_history),
 1349            ..self
 1350        }
 1351    }
 1352}
 1353
 1354struct DeferredSelectionEffectsState {
 1355    changed: bool,
 1356    effects: SelectionEffects,
 1357    old_cursor_position: Anchor,
 1358    history_entry: SelectionHistoryEntry,
 1359}
 1360
 1361#[derive(Default)]
 1362struct SelectionHistory {
 1363    #[allow(clippy::type_complexity)]
 1364    selections_by_transaction:
 1365        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1366    mode: SelectionHistoryMode,
 1367    undo_stack: VecDeque<SelectionHistoryEntry>,
 1368    redo_stack: VecDeque<SelectionHistoryEntry>,
 1369}
 1370
 1371impl SelectionHistory {
 1372    #[track_caller]
 1373    fn insert_transaction(
 1374        &mut self,
 1375        transaction_id: TransactionId,
 1376        selections: Arc<[Selection<Anchor>]>,
 1377    ) {
 1378        if selections.is_empty() {
 1379            log::error!(
 1380                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1381                std::panic::Location::caller()
 1382            );
 1383            return;
 1384        }
 1385        self.selections_by_transaction
 1386            .insert(transaction_id, (selections, None));
 1387    }
 1388
 1389    #[allow(clippy::type_complexity)]
 1390    fn transaction(
 1391        &self,
 1392        transaction_id: TransactionId,
 1393    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1394        self.selections_by_transaction.get(&transaction_id)
 1395    }
 1396
 1397    #[allow(clippy::type_complexity)]
 1398    fn transaction_mut(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1402        self.selections_by_transaction.get_mut(&transaction_id)
 1403    }
 1404
 1405    fn push(&mut self, entry: SelectionHistoryEntry) {
 1406        if !entry.selections.is_empty() {
 1407            match self.mode {
 1408                SelectionHistoryMode::Normal => {
 1409                    self.push_undo(entry);
 1410                    self.redo_stack.clear();
 1411                }
 1412                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1413                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1414                SelectionHistoryMode::Skipping => {}
 1415            }
 1416        }
 1417    }
 1418
 1419    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1420        if self
 1421            .undo_stack
 1422            .back()
 1423            .map_or(true, |e| e.selections != entry.selections)
 1424        {
 1425            self.undo_stack.push_back(entry);
 1426            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1427                self.undo_stack.pop_front();
 1428            }
 1429        }
 1430    }
 1431
 1432    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1433        if self
 1434            .redo_stack
 1435            .back()
 1436            .map_or(true, |e| e.selections != entry.selections)
 1437        {
 1438            self.redo_stack.push_back(entry);
 1439            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1440                self.redo_stack.pop_front();
 1441            }
 1442        }
 1443    }
 1444}
 1445
 1446#[derive(Clone, Copy)]
 1447pub struct RowHighlightOptions {
 1448    pub autoscroll: bool,
 1449    pub include_gutter: bool,
 1450}
 1451
 1452impl Default for RowHighlightOptions {
 1453    fn default() -> Self {
 1454        Self {
 1455            autoscroll: Default::default(),
 1456            include_gutter: true,
 1457        }
 1458    }
 1459}
 1460
 1461struct RowHighlight {
 1462    index: usize,
 1463    range: Range<Anchor>,
 1464    color: Hsla,
 1465    options: RowHighlightOptions,
 1466    type_id: TypeId,
 1467}
 1468
 1469#[derive(Clone, Debug)]
 1470struct AddSelectionsState {
 1471    groups: Vec<AddSelectionsGroup>,
 1472}
 1473
 1474#[derive(Clone, Debug)]
 1475struct AddSelectionsGroup {
 1476    above: bool,
 1477    stack: Vec<usize>,
 1478}
 1479
 1480#[derive(Clone)]
 1481struct SelectNextState {
 1482    query: AhoCorasick,
 1483    wordwise: bool,
 1484    done: bool,
 1485}
 1486
 1487impl std::fmt::Debug for SelectNextState {
 1488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1489        f.debug_struct(std::any::type_name::<Self>())
 1490            .field("wordwise", &self.wordwise)
 1491            .field("done", &self.done)
 1492            .finish()
 1493    }
 1494}
 1495
 1496#[derive(Debug)]
 1497struct AutocloseRegion {
 1498    selection_id: usize,
 1499    range: Range<Anchor>,
 1500    pair: BracketPair,
 1501}
 1502
 1503#[derive(Debug)]
 1504struct SnippetState {
 1505    ranges: Vec<Vec<Range<Anchor>>>,
 1506    active_index: usize,
 1507    choices: Vec<Option<Vec<String>>>,
 1508}
 1509
 1510#[doc(hidden)]
 1511pub struct RenameState {
 1512    pub range: Range<Anchor>,
 1513    pub old_name: Arc<str>,
 1514    pub editor: Entity<Editor>,
 1515    block_id: CustomBlockId,
 1516}
 1517
 1518struct InvalidationStack<T>(Vec<T>);
 1519
 1520struct RegisteredInlineCompletionProvider {
 1521    provider: Arc<dyn InlineCompletionProviderHandle>,
 1522    _subscription: Subscription,
 1523}
 1524
 1525#[derive(Debug, PartialEq, Eq)]
 1526pub struct ActiveDiagnosticGroup {
 1527    pub active_range: Range<Anchor>,
 1528    pub active_message: String,
 1529    pub group_id: usize,
 1530    pub blocks: HashSet<CustomBlockId>,
 1531}
 1532
 1533#[derive(Debug, PartialEq, Eq)]
 1534
 1535pub(crate) enum ActiveDiagnostic {
 1536    None,
 1537    All,
 1538    Group(ActiveDiagnosticGroup),
 1539}
 1540
 1541#[derive(Serialize, Deserialize, Clone, Debug)]
 1542pub struct ClipboardSelection {
 1543    /// The number of bytes in this selection.
 1544    pub len: usize,
 1545    /// Whether this was a full-line selection.
 1546    pub is_entire_line: bool,
 1547    /// The indentation of the first line when this content was originally copied.
 1548    pub first_line_indent: u32,
 1549}
 1550
 1551// selections, scroll behavior, was newest selection reversed
 1552type SelectSyntaxNodeHistoryState = (
 1553    Box<[Selection<usize>]>,
 1554    SelectSyntaxNodeScrollBehavior,
 1555    bool,
 1556);
 1557
 1558#[derive(Default)]
 1559struct SelectSyntaxNodeHistory {
 1560    stack: Vec<SelectSyntaxNodeHistoryState>,
 1561    // disable temporarily to allow changing selections without losing the stack
 1562    pub disable_clearing: bool,
 1563}
 1564
 1565impl SelectSyntaxNodeHistory {
 1566    pub fn try_clear(&mut self) {
 1567        if !self.disable_clearing {
 1568            self.stack.clear();
 1569        }
 1570    }
 1571
 1572    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1573        self.stack.push(selection);
 1574    }
 1575
 1576    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1577        self.stack.pop()
 1578    }
 1579}
 1580
 1581enum SelectSyntaxNodeScrollBehavior {
 1582    CursorTop,
 1583    FitSelection,
 1584    CursorBottom,
 1585}
 1586
 1587#[derive(Debug)]
 1588pub(crate) struct NavigationData {
 1589    cursor_anchor: Anchor,
 1590    cursor_position: Point,
 1591    scroll_anchor: ScrollAnchor,
 1592    scroll_top_row: u32,
 1593}
 1594
 1595#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1596pub enum GotoDefinitionKind {
 1597    Symbol,
 1598    Declaration,
 1599    Type,
 1600    Implementation,
 1601}
 1602
 1603#[derive(Debug, Clone)]
 1604enum InlayHintRefreshReason {
 1605    ModifiersChanged(bool),
 1606    Toggle(bool),
 1607    SettingsChange(InlayHintSettings),
 1608    NewLinesShown,
 1609    BufferEdited(HashSet<Arc<Language>>),
 1610    RefreshRequested,
 1611    ExcerptsRemoved(Vec<ExcerptId>),
 1612}
 1613
 1614impl InlayHintRefreshReason {
 1615    fn description(&self) -> &'static str {
 1616        match self {
 1617            Self::ModifiersChanged(_) => "modifiers changed",
 1618            Self::Toggle(_) => "toggle",
 1619            Self::SettingsChange(_) => "settings change",
 1620            Self::NewLinesShown => "new lines shown",
 1621            Self::BufferEdited(_) => "buffer edited",
 1622            Self::RefreshRequested => "refresh requested",
 1623            Self::ExcerptsRemoved(_) => "excerpts removed",
 1624        }
 1625    }
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    fn new_internal(
 1769        mode: EditorMode,
 1770        buffer: Entity<MultiBuffer>,
 1771        project: Option<Entity<Project>>,
 1772        display_map: Option<Entity<DisplayMap>>,
 1773        window: &mut Window,
 1774        cx: &mut Context<Self>,
 1775    ) -> Self {
 1776        debug_assert!(
 1777            display_map.is_none() || mode.is_minimap(),
 1778            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1779        );
 1780
 1781        let full_mode = mode.is_full();
 1782        let is_minimap = mode.is_minimap();
 1783        let diagnostics_max_severity = if full_mode {
 1784            EditorSettings::get_global(cx)
 1785                .diagnostics_max_severity
 1786                .unwrap_or(DiagnosticSeverity::Hint)
 1787        } else {
 1788            DiagnosticSeverity::Off
 1789        };
 1790        let style = window.text_style();
 1791        let font_size = style.font_size.to_pixels(window.rem_size());
 1792        let editor = cx.entity().downgrade();
 1793        let fold_placeholder = FoldPlaceholder {
 1794            constrain_width: true,
 1795            render: Arc::new(move |fold_id, fold_range, cx| {
 1796                let editor = editor.clone();
 1797                div()
 1798                    .id(fold_id)
 1799                    .bg(cx.theme().colors().ghost_element_background)
 1800                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1801                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1802                    .rounded_xs()
 1803                    .size_full()
 1804                    .cursor_pointer()
 1805                    .child("")
 1806                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1807                    .on_click(move |_, _window, cx| {
 1808                        editor
 1809                            .update(cx, |editor, cx| {
 1810                                editor.unfold_ranges(
 1811                                    &[fold_range.start..fold_range.end],
 1812                                    true,
 1813                                    false,
 1814                                    cx,
 1815                                );
 1816                                cx.stop_propagation();
 1817                            })
 1818                            .ok();
 1819                    })
 1820                    .into_any()
 1821            }),
 1822            merge_adjacent: true,
 1823            ..FoldPlaceholder::default()
 1824        };
 1825        let display_map = display_map.unwrap_or_else(|| {
 1826            cx.new(|cx| {
 1827                DisplayMap::new(
 1828                    buffer.clone(),
 1829                    style.font(),
 1830                    font_size,
 1831                    None,
 1832                    FILE_HEADER_HEIGHT,
 1833                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1834                    fold_placeholder,
 1835                    diagnostics_max_severity,
 1836                    cx,
 1837                )
 1838            })
 1839        });
 1840
 1841        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1842
 1843        let blink_manager = cx.new(|cx| {
 1844            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1845            if is_minimap {
 1846                blink_manager.disable(cx);
 1847            }
 1848            blink_manager
 1849        });
 1850
 1851        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1852            .then(|| language_settings::SoftWrap::None);
 1853
 1854        let mut project_subscriptions = Vec::new();
 1855        if full_mode {
 1856            if let Some(project) = project.as_ref() {
 1857                project_subscriptions.push(cx.subscribe_in(
 1858                    project,
 1859                    window,
 1860                    |editor, _, event, window, cx| match event {
 1861                        project::Event::RefreshCodeLens => {
 1862                            // we always query lens with actions, without storing them, always refreshing them
 1863                        }
 1864                        project::Event::RefreshInlayHints => {
 1865                            editor
 1866                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1867                        }
 1868                        project::Event::LanguageServerAdded(..)
 1869                        | project::Event::LanguageServerRemoved(..) => {
 1870                            if editor.tasks_update_task.is_none() {
 1871                                editor.tasks_update_task =
 1872                                    Some(editor.refresh_runnables(window, cx));
 1873                            }
 1874                            editor.update_lsp_data(true, None, window, cx);
 1875                        }
 1876                        project::Event::SnippetEdit(id, snippet_edits) => {
 1877                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                                let focus_handle = editor.focus_handle(cx);
 1879                                if focus_handle.is_focused(window) {
 1880                                    let snapshot = buffer.read(cx).snapshot();
 1881                                    for (range, snippet) in snippet_edits {
 1882                                        let editor_range =
 1883                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                        editor
 1885                                            .insert_snippet(
 1886                                                &[editor_range],
 1887                                                snippet.clone(),
 1888                                                window,
 1889                                                cx,
 1890                                            )
 1891                                            .ok();
 1892                                    }
 1893                                }
 1894                            }
 1895                        }
 1896                        _ => {}
 1897                    },
 1898                ));
 1899                if let Some(task_inventory) = project
 1900                    .read(cx)
 1901                    .task_store()
 1902                    .read(cx)
 1903                    .task_inventory()
 1904                    .cloned()
 1905                {
 1906                    project_subscriptions.push(cx.observe_in(
 1907                        &task_inventory,
 1908                        window,
 1909                        |editor, _, window, cx| {
 1910                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1911                        },
 1912                    ));
 1913                };
 1914
 1915                project_subscriptions.push(cx.subscribe_in(
 1916                    &project.read(cx).breakpoint_store(),
 1917                    window,
 1918                    |editor, _, event, window, cx| match event {
 1919                        BreakpointStoreEvent::ClearDebugLines => {
 1920                            editor.clear_row_highlights::<ActiveDebugLine>();
 1921                            editor.refresh_inline_values(cx);
 1922                        }
 1923                        BreakpointStoreEvent::SetDebugLine => {
 1924                            if editor.go_to_active_debug_line(window, cx) {
 1925                                cx.stop_propagation();
 1926                            }
 1927
 1928                            editor.refresh_inline_values(cx);
 1929                        }
 1930                        _ => {}
 1931                    },
 1932                ));
 1933                let git_store = project.read(cx).git_store().clone();
 1934                let project = project.clone();
 1935                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1936                    match event {
 1937                        GitStoreEvent::RepositoryUpdated(
 1938                            _,
 1939                            RepositoryEvent::Updated {
 1940                                new_instance: true, ..
 1941                            },
 1942                            _,
 1943                        ) => {
 1944                            this.load_diff_task = Some(
 1945                                update_uncommitted_diff_for_buffer(
 1946                                    cx.entity(),
 1947                                    &project,
 1948                                    this.buffer.read(cx).all_buffers(),
 1949                                    this.buffer.clone(),
 1950                                    cx,
 1951                                )
 1952                                .shared(),
 1953                            );
 1954                        }
 1955                        _ => {}
 1956                    }
 1957                }));
 1958            }
 1959        }
 1960
 1961        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1962
 1963        let inlay_hint_settings =
 1964            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1965        let focus_handle = cx.focus_handle();
 1966        if !is_minimap {
 1967            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1968                .detach();
 1969            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1970                .detach();
 1971            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1972                .detach();
 1973            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1974                .detach();
 1975            cx.observe_pending_input(window, Self::observe_pending_input)
 1976                .detach();
 1977        }
 1978
 1979        let show_indent_guides = if matches!(
 1980            mode,
 1981            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1982        ) {
 1983            Some(false)
 1984        } else {
 1985            None
 1986        };
 1987
 1988        let breakpoint_store = match (&mode, project.as_ref()) {
 1989            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1990            _ => None,
 1991        };
 1992
 1993        let mut code_action_providers = Vec::new();
 1994        let mut load_uncommitted_diff = None;
 1995        if let Some(project) = project.clone() {
 1996            load_uncommitted_diff = Some(
 1997                update_uncommitted_diff_for_buffer(
 1998                    cx.entity(),
 1999                    &project,
 2000                    buffer.read(cx).all_buffers(),
 2001                    buffer.clone(),
 2002                    cx,
 2003                )
 2004                .shared(),
 2005            );
 2006            code_action_providers.push(Rc::new(project) as Rc<_>);
 2007        }
 2008
 2009        let mut editor = Self {
 2010            focus_handle,
 2011            show_cursor_when_unfocused: false,
 2012            last_focused_descendant: None,
 2013            buffer: buffer.clone(),
 2014            display_map: display_map.clone(),
 2015            selections,
 2016            scroll_manager: ScrollManager::new(cx),
 2017            columnar_selection_state: None,
 2018            add_selections_state: None,
 2019            select_next_state: None,
 2020            select_prev_state: None,
 2021            selection_history: SelectionHistory::default(),
 2022            defer_selection_effects: false,
 2023            deferred_selection_effects_state: None,
 2024            autoclose_regions: Vec::new(),
 2025            snippet_stack: InvalidationStack::default(),
 2026            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2027            ime_transaction: None,
 2028            active_diagnostics: ActiveDiagnostic::None,
 2029            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2030            inline_diagnostics_update: Task::ready(()),
 2031            inline_diagnostics: Vec::new(),
 2032            soft_wrap_mode_override,
 2033            diagnostics_max_severity,
 2034            hard_wrap: None,
 2035            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2037            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2038            project,
 2039            blink_manager: blink_manager.clone(),
 2040            show_local_selections: true,
 2041            show_scrollbars: ScrollbarAxes {
 2042                horizontal: full_mode,
 2043                vertical: full_mode,
 2044            },
 2045            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2046            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2047            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2048            show_gutter: full_mode,
 2049            show_line_numbers: (!full_mode).then_some(false),
 2050            use_relative_line_numbers: None,
 2051            disable_expand_excerpt_buttons: !full_mode,
 2052            show_git_diff_gutter: None,
 2053            show_code_actions: None,
 2054            show_runnables: None,
 2055            show_breakpoints: None,
 2056            show_wrap_guides: None,
 2057            show_indent_guides,
 2058            placeholder_text: None,
 2059            highlight_order: 0,
 2060            highlighted_rows: HashMap::default(),
 2061            background_highlights: TreeMap::default(),
 2062            gutter_highlights: TreeMap::default(),
 2063            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2064            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2065            nav_history: None,
 2066            context_menu: RefCell::new(None),
 2067            context_menu_options: None,
 2068            mouse_context_menu: None,
 2069            completion_tasks: Vec::new(),
 2070            inline_blame_popover: None,
 2071            inline_blame_popover_show_task: None,
 2072            signature_help_state: SignatureHelpState::default(),
 2073            auto_signature_help: None,
 2074            find_all_references_task_sources: Vec::new(),
 2075            next_completion_id: 0,
 2076            next_inlay_id: 0,
 2077            code_action_providers,
 2078            available_code_actions: None,
 2079            code_actions_task: None,
 2080            quick_selection_highlight_task: None,
 2081            debounced_selection_highlight_task: None,
 2082            document_highlights_task: None,
 2083            linked_editing_range_task: None,
 2084            pending_rename: None,
 2085            searchable: !is_minimap,
 2086            cursor_shape: EditorSettings::get_global(cx)
 2087                .cursor_shape
 2088                .unwrap_or_default(),
 2089            current_line_highlight: None,
 2090            autoindent_mode: Some(AutoindentMode::EachLine),
 2091            collapse_matches: false,
 2092            workspace: None,
 2093            input_enabled: !is_minimap,
 2094            use_modal_editing: full_mode,
 2095            read_only: is_minimap,
 2096            use_autoclose: true,
 2097            use_auto_surround: true,
 2098            auto_replace_emoji_shortcode: false,
 2099            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2100            leader_id: None,
 2101            remote_id: None,
 2102            hover_state: HoverState::default(),
 2103            pending_mouse_down: None,
 2104            hovered_link_state: None,
 2105            edit_prediction_provider: None,
 2106            active_inline_completion: None,
 2107            stale_inline_completion_in_menu: None,
 2108            edit_prediction_preview: EditPredictionPreview::Inactive {
 2109                released_too_fast: false,
 2110            },
 2111            inline_diagnostics_enabled: full_mode,
 2112            diagnostics_enabled: full_mode,
 2113            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2114            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2115            gutter_hovered: false,
 2116            pixel_position_of_newest_cursor: None,
 2117            last_bounds: None,
 2118            last_position_map: None,
 2119            expect_bounds_change: None,
 2120            gutter_dimensions: GutterDimensions::default(),
 2121            style: None,
 2122            show_cursor_names: false,
 2123            hovered_cursors: HashMap::default(),
 2124            next_editor_action_id: EditorActionId::default(),
 2125            editor_actions: Rc::default(),
 2126            inline_completions_hidden_for_vim_mode: false,
 2127            show_inline_completions_override: None,
 2128            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2129            edit_prediction_settings: EditPredictionSettings::Disabled,
 2130            edit_prediction_indent_conflict: false,
 2131            edit_prediction_requires_modifier_in_indent_conflict: true,
 2132            custom_context_menu: None,
 2133            show_git_blame_gutter: false,
 2134            show_git_blame_inline: false,
 2135            show_selection_menu: None,
 2136            show_git_blame_inline_delay_task: None,
 2137            git_blame_inline_enabled: full_mode
 2138                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2139            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2140            serialize_dirty_buffers: !is_minimap
 2141                && ProjectSettings::get_global(cx)
 2142                    .session
 2143                    .restore_unsaved_buffers,
 2144            blame: None,
 2145            blame_subscription: None,
 2146            tasks: BTreeMap::default(),
 2147
 2148            breakpoint_store,
 2149            gutter_breakpoint_indicator: (None, None),
 2150            hovered_diff_hunk_row: None,
 2151            _subscriptions: (!is_minimap)
 2152                .then(|| {
 2153                    vec![
 2154                        cx.observe(&buffer, Self::on_buffer_changed),
 2155                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2156                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2157                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2158                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2159                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2160                        cx.observe_window_activation(window, |editor, window, cx| {
 2161                            let active = window.is_window_active();
 2162                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2163                                if active {
 2164                                    blink_manager.enable(cx);
 2165                                } else {
 2166                                    blink_manager.disable(cx);
 2167                                }
 2168                            });
 2169                            if active {
 2170                                editor.show_mouse_cursor(cx);
 2171                            }
 2172                        }),
 2173                    ]
 2174                })
 2175                .unwrap_or_default(),
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206
 2207        if is_minimap {
 2208            return editor;
 2209        }
 2210
 2211        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2212            editor
 2213                ._subscriptions
 2214                .push(cx.observe(breakpoints, |_, _, cx| {
 2215                    cx.notify();
 2216                }));
 2217        }
 2218        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2219        editor._subscriptions.extend(project_subscriptions);
 2220
 2221        editor._subscriptions.push(cx.subscribe_in(
 2222            &cx.entity(),
 2223            window,
 2224            |editor, _, e: &EditorEvent, window, cx| match e {
 2225                EditorEvent::ScrollPositionChanged { local, .. } => {
 2226                    if *local {
 2227                        let new_anchor = editor.scroll_manager.anchor();
 2228                        let snapshot = editor.snapshot(window, cx);
 2229                        editor.update_restoration_data(cx, move |data| {
 2230                            data.scroll_position = (
 2231                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2232                                new_anchor.offset,
 2233                            );
 2234                        });
 2235                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2236                        editor.inline_blame_popover.take();
 2237                    }
 2238                }
 2239                EditorEvent::Edited { .. } => {
 2240                    if !vim_enabled(cx) {
 2241                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2242                        let pop_state = editor
 2243                            .change_list
 2244                            .last()
 2245                            .map(|previous| {
 2246                                previous.len() == selections.len()
 2247                                    && previous.iter().enumerate().all(|(ix, p)| {
 2248                                        p.to_display_point(&map).row()
 2249                                            == selections[ix].head().row()
 2250                                    })
 2251                            })
 2252                            .unwrap_or(false);
 2253                        let new_positions = selections
 2254                            .into_iter()
 2255                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2256                            .collect();
 2257                        editor
 2258                            .change_list
 2259                            .push_to_change_list(pop_state, new_positions);
 2260                    }
 2261                }
 2262                _ => (),
 2263            },
 2264        ));
 2265
 2266        if let Some(dap_store) = editor
 2267            .project
 2268            .as_ref()
 2269            .map(|project| project.read(cx).dap_store())
 2270        {
 2271            let weak_editor = cx.weak_entity();
 2272
 2273            editor
 2274                ._subscriptions
 2275                .push(
 2276                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2277                        let session_entity = cx.entity();
 2278                        weak_editor
 2279                            .update(cx, |editor, cx| {
 2280                                editor._subscriptions.push(
 2281                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2282                                );
 2283                            })
 2284                            .ok();
 2285                    }),
 2286                );
 2287
 2288            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2289                editor
 2290                    ._subscriptions
 2291                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2292            }
 2293        }
 2294
 2295        // skip adding the initial selection to selection history
 2296        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2297        editor.end_selection(window, cx);
 2298        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2299
 2300        editor.scroll_manager.show_scrollbars(window, cx);
 2301        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2302
 2303        if full_mode {
 2304            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2305            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2306
 2307            if editor.git_blame_inline_enabled {
 2308                editor.start_git_blame_inline(false, window, cx);
 2309            }
 2310
 2311            editor.go_to_active_debug_line(window, cx);
 2312
 2313            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2314                if let Some(project) = editor.project.as_ref() {
 2315                    let handle = project.update(cx, |project, cx| {
 2316                        project.register_buffer_with_language_servers(&buffer, cx)
 2317                    });
 2318                    editor
 2319                        .registered_buffers
 2320                        .insert(buffer.read(cx).remote_id(), handle);
 2321                }
 2322            }
 2323
 2324            editor.minimap =
 2325                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2326            editor.colors = Some(LspColorData::new(cx));
 2327            editor.update_lsp_data(false, None, window, cx);
 2328        }
 2329
 2330        if editor.mode.is_full() {
 2331            editor.report_editor_event("Editor Opened", None, cx);
 2332        }
 2333
 2334        editor
 2335    }
 2336
 2337    pub fn deploy_mouse_context_menu(
 2338        &mut self,
 2339        position: gpui::Point<Pixels>,
 2340        context_menu: Entity<ContextMenu>,
 2341        window: &mut Window,
 2342        cx: &mut Context<Self>,
 2343    ) {
 2344        self.mouse_context_menu = Some(MouseContextMenu::new(
 2345            self,
 2346            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2347            context_menu,
 2348            window,
 2349            cx,
 2350        ));
 2351    }
 2352
 2353    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2354        self.mouse_context_menu
 2355            .as_ref()
 2356            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2357    }
 2358
 2359    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2360        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2361    }
 2362
 2363    fn key_context_internal(
 2364        &self,
 2365        has_active_edit_prediction: bool,
 2366        window: &Window,
 2367        cx: &App,
 2368    ) -> KeyContext {
 2369        let mut key_context = KeyContext::new_with_defaults();
 2370        key_context.add("Editor");
 2371        let mode = match self.mode {
 2372            EditorMode::SingleLine { .. } => "single_line",
 2373            EditorMode::AutoHeight { .. } => "auto_height",
 2374            EditorMode::Minimap { .. } => "minimap",
 2375            EditorMode::Full { .. } => "full",
 2376        };
 2377
 2378        if EditorSettings::jupyter_enabled(cx) {
 2379            key_context.add("jupyter");
 2380        }
 2381
 2382        key_context.set("mode", mode);
 2383        if self.pending_rename.is_some() {
 2384            key_context.add("renaming");
 2385        }
 2386
 2387        match self.context_menu.borrow().as_ref() {
 2388            Some(CodeContextMenu::Completions(menu)) => {
 2389                if menu.visible() {
 2390                    key_context.add("menu");
 2391                    key_context.add("showing_completions");
 2392                }
 2393            }
 2394            Some(CodeContextMenu::CodeActions(menu)) => {
 2395                if menu.visible() {
 2396                    key_context.add("menu");
 2397                    key_context.add("showing_code_actions")
 2398                }
 2399            }
 2400            None => {}
 2401        }
 2402
 2403        if self.signature_help_state.has_multiple_signatures() {
 2404            key_context.add("showing_signature_help");
 2405        }
 2406
 2407        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2408        if !self.focus_handle(cx).contains_focused(window, cx)
 2409            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2410        {
 2411            for addon in self.addons.values() {
 2412                addon.extend_key_context(&mut key_context, cx)
 2413            }
 2414        }
 2415
 2416        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2417            if let Some(extension) = singleton_buffer
 2418                .read(cx)
 2419                .file()
 2420                .and_then(|file| file.path().extension()?.to_str())
 2421            {
 2422                key_context.set("extension", extension.to_string());
 2423            }
 2424        } else {
 2425            key_context.add("multibuffer");
 2426        }
 2427
 2428        if has_active_edit_prediction {
 2429            if self.edit_prediction_in_conflict() {
 2430                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2431            } else {
 2432                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2433                key_context.add("copilot_suggestion");
 2434            }
 2435        }
 2436
 2437        if self.selection_mark_mode {
 2438            key_context.add("selection_mode");
 2439        }
 2440
 2441        key_context
 2442    }
 2443
 2444    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2445        if self.mouse_cursor_hidden {
 2446            self.mouse_cursor_hidden = false;
 2447            cx.notify();
 2448        }
 2449    }
 2450
 2451    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2452        let hide_mouse_cursor = match origin {
 2453            HideMouseCursorOrigin::TypingAction => {
 2454                matches!(
 2455                    self.hide_mouse_mode,
 2456                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2457                )
 2458            }
 2459            HideMouseCursorOrigin::MovementAction => {
 2460                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2461            }
 2462        };
 2463        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2464            self.mouse_cursor_hidden = hide_mouse_cursor;
 2465            cx.notify();
 2466        }
 2467    }
 2468
 2469    pub fn edit_prediction_in_conflict(&self) -> bool {
 2470        if !self.show_edit_predictions_in_menu() {
 2471            return false;
 2472        }
 2473
 2474        let showing_completions = self
 2475            .context_menu
 2476            .borrow()
 2477            .as_ref()
 2478            .map_or(false, |context| {
 2479                matches!(context, CodeContextMenu::Completions(_))
 2480            });
 2481
 2482        showing_completions
 2483            || self.edit_prediction_requires_modifier()
 2484            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2485            // bindings to insert tab characters.
 2486            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2487    }
 2488
 2489    pub fn accept_edit_prediction_keybind(
 2490        &self,
 2491        accept_partial: bool,
 2492        window: &Window,
 2493        cx: &App,
 2494    ) -> AcceptEditPredictionBinding {
 2495        let key_context = self.key_context_internal(true, window, cx);
 2496        let in_conflict = self.edit_prediction_in_conflict();
 2497
 2498        let bindings = if accept_partial {
 2499            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2500        } else {
 2501            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2502        };
 2503
 2504        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2505        // just the first one.
 2506        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2507            !in_conflict
 2508                || binding
 2509                    .keystrokes()
 2510                    .first()
 2511                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2512        }))
 2513    }
 2514
 2515    pub fn new_file(
 2516        workspace: &mut Workspace,
 2517        _: &workspace::NewFile,
 2518        window: &mut Window,
 2519        cx: &mut Context<Workspace>,
 2520    ) {
 2521        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2522            "Failed to create buffer",
 2523            window,
 2524            cx,
 2525            |e, _, _| match e.error_code() {
 2526                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2527                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2528                e.error_tag("required").unwrap_or("the latest version")
 2529            )),
 2530                _ => None,
 2531            },
 2532        );
 2533    }
 2534
 2535    pub fn new_in_workspace(
 2536        workspace: &mut Workspace,
 2537        window: &mut Window,
 2538        cx: &mut Context<Workspace>,
 2539    ) -> Task<Result<Entity<Editor>>> {
 2540        let project = workspace.project().clone();
 2541        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2542
 2543        cx.spawn_in(window, async move |workspace, cx| {
 2544            let buffer = create.await?;
 2545            workspace.update_in(cx, |workspace, window, cx| {
 2546                let editor =
 2547                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2548                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2549                editor
 2550            })
 2551        })
 2552    }
 2553
 2554    fn new_file_vertical(
 2555        workspace: &mut Workspace,
 2556        _: &workspace::NewFileSplitVertical,
 2557        window: &mut Window,
 2558        cx: &mut Context<Workspace>,
 2559    ) {
 2560        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2561    }
 2562
 2563    fn new_file_horizontal(
 2564        workspace: &mut Workspace,
 2565        _: &workspace::NewFileSplitHorizontal,
 2566        window: &mut Window,
 2567        cx: &mut Context<Workspace>,
 2568    ) {
 2569        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2570    }
 2571
 2572    fn new_file_in_direction(
 2573        workspace: &mut Workspace,
 2574        direction: SplitDirection,
 2575        window: &mut Window,
 2576        cx: &mut Context<Workspace>,
 2577    ) {
 2578        let project = workspace.project().clone();
 2579        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2580
 2581        cx.spawn_in(window, async move |workspace, cx| {
 2582            let buffer = create.await?;
 2583            workspace.update_in(cx, move |workspace, window, cx| {
 2584                workspace.split_item(
 2585                    direction,
 2586                    Box::new(
 2587                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2588                    ),
 2589                    window,
 2590                    cx,
 2591                )
 2592            })?;
 2593            anyhow::Ok(())
 2594        })
 2595        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2596            match e.error_code() {
 2597                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2598                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2599                e.error_tag("required").unwrap_or("the latest version")
 2600            )),
 2601                _ => None,
 2602            }
 2603        });
 2604    }
 2605
 2606    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2607        self.leader_id
 2608    }
 2609
 2610    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2611        &self.buffer
 2612    }
 2613
 2614    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2615        self.workspace.as_ref()?.0.upgrade()
 2616    }
 2617
 2618    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2619        self.buffer().read(cx).title(cx)
 2620    }
 2621
 2622    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2623        let git_blame_gutter_max_author_length = self
 2624            .render_git_blame_gutter(cx)
 2625            .then(|| {
 2626                if let Some(blame) = self.blame.as_ref() {
 2627                    let max_author_length =
 2628                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2629                    Some(max_author_length)
 2630                } else {
 2631                    None
 2632                }
 2633            })
 2634            .flatten();
 2635
 2636        EditorSnapshot {
 2637            mode: self.mode.clone(),
 2638            show_gutter: self.show_gutter,
 2639            show_line_numbers: self.show_line_numbers,
 2640            show_git_diff_gutter: self.show_git_diff_gutter,
 2641            show_code_actions: self.show_code_actions,
 2642            show_runnables: self.show_runnables,
 2643            show_breakpoints: self.show_breakpoints,
 2644            git_blame_gutter_max_author_length,
 2645            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2646            scroll_anchor: self.scroll_manager.anchor(),
 2647            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2648            placeholder_text: self.placeholder_text.clone(),
 2649            is_focused: self.focus_handle.is_focused(window),
 2650            current_line_highlight: self
 2651                .current_line_highlight
 2652                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2653            gutter_hovered: self.gutter_hovered,
 2654        }
 2655    }
 2656
 2657    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2658        self.buffer.read(cx).language_at(point, cx)
 2659    }
 2660
 2661    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2662        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2663    }
 2664
 2665    pub fn active_excerpt(
 2666        &self,
 2667        cx: &App,
 2668    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2669        self.buffer
 2670            .read(cx)
 2671            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2672    }
 2673
 2674    pub fn mode(&self) -> &EditorMode {
 2675        &self.mode
 2676    }
 2677
 2678    pub fn set_mode(&mut self, mode: EditorMode) {
 2679        self.mode = mode;
 2680    }
 2681
 2682    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2683        self.collaboration_hub.as_deref()
 2684    }
 2685
 2686    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2687        self.collaboration_hub = Some(hub);
 2688    }
 2689
 2690    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2691        self.in_project_search = in_project_search;
 2692    }
 2693
 2694    pub fn set_custom_context_menu(
 2695        &mut self,
 2696        f: impl 'static
 2697        + Fn(
 2698            &mut Self,
 2699            DisplayPoint,
 2700            &mut Window,
 2701            &mut Context<Self>,
 2702        ) -> Option<Entity<ui::ContextMenu>>,
 2703    ) {
 2704        self.custom_context_menu = Some(Box::new(f))
 2705    }
 2706
 2707    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2708        self.completion_provider = provider;
 2709    }
 2710
 2711    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2712        self.semantics_provider.clone()
 2713    }
 2714
 2715    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2716        self.semantics_provider = provider;
 2717    }
 2718
 2719    pub fn set_edit_prediction_provider<T>(
 2720        &mut self,
 2721        provider: Option<Entity<T>>,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) where
 2725        T: EditPredictionProvider,
 2726    {
 2727        self.edit_prediction_provider =
 2728            provider.map(|provider| RegisteredInlineCompletionProvider {
 2729                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2730                    if this.focus_handle.is_focused(window) {
 2731                        this.update_visible_inline_completion(window, cx);
 2732                    }
 2733                }),
 2734                provider: Arc::new(provider),
 2735            });
 2736        self.update_edit_prediction_settings(cx);
 2737        self.refresh_inline_completion(false, false, window, cx);
 2738    }
 2739
 2740    pub fn placeholder_text(&self) -> Option<&str> {
 2741        self.placeholder_text.as_deref()
 2742    }
 2743
 2744    pub fn set_placeholder_text(
 2745        &mut self,
 2746        placeholder_text: impl Into<Arc<str>>,
 2747        cx: &mut Context<Self>,
 2748    ) {
 2749        let placeholder_text = Some(placeholder_text.into());
 2750        if self.placeholder_text != placeholder_text {
 2751            self.placeholder_text = placeholder_text;
 2752            cx.notify();
 2753        }
 2754    }
 2755
 2756    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2757        self.cursor_shape = cursor_shape;
 2758
 2759        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2760        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2761
 2762        cx.notify();
 2763    }
 2764
 2765    pub fn set_current_line_highlight(
 2766        &mut self,
 2767        current_line_highlight: Option<CurrentLineHighlight>,
 2768    ) {
 2769        self.current_line_highlight = current_line_highlight;
 2770    }
 2771
 2772    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2773        self.collapse_matches = collapse_matches;
 2774    }
 2775
 2776    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2777        let buffers = self.buffer.read(cx).all_buffers();
 2778        let Some(project) = self.project.as_ref() else {
 2779            return;
 2780        };
 2781        project.update(cx, |project, cx| {
 2782            for buffer in buffers {
 2783                self.registered_buffers
 2784                    .entry(buffer.read(cx).remote_id())
 2785                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2786            }
 2787        })
 2788    }
 2789
 2790    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2791        if self.collapse_matches {
 2792            return range.start..range.start;
 2793        }
 2794        range.clone()
 2795    }
 2796
 2797    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2798        if self.display_map.read(cx).clip_at_line_ends != clip {
 2799            self.display_map
 2800                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2801        }
 2802    }
 2803
 2804    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2805        self.input_enabled = input_enabled;
 2806    }
 2807
 2808    pub fn set_inline_completions_hidden_for_vim_mode(
 2809        &mut self,
 2810        hidden: bool,
 2811        window: &mut Window,
 2812        cx: &mut Context<Self>,
 2813    ) {
 2814        if hidden != self.inline_completions_hidden_for_vim_mode {
 2815            self.inline_completions_hidden_for_vim_mode = hidden;
 2816            if hidden {
 2817                self.update_visible_inline_completion(window, cx);
 2818            } else {
 2819                self.refresh_inline_completion(true, false, window, cx);
 2820            }
 2821        }
 2822    }
 2823
 2824    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2825        self.menu_inline_completions_policy = value;
 2826    }
 2827
 2828    pub fn set_autoindent(&mut self, autoindent: bool) {
 2829        if autoindent {
 2830            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2831        } else {
 2832            self.autoindent_mode = None;
 2833        }
 2834    }
 2835
 2836    pub fn read_only(&self, cx: &App) -> bool {
 2837        self.read_only || self.buffer.read(cx).read_only()
 2838    }
 2839
 2840    pub fn set_read_only(&mut self, read_only: bool) {
 2841        self.read_only = read_only;
 2842    }
 2843
 2844    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2845        self.use_autoclose = autoclose;
 2846    }
 2847
 2848    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2849        self.use_auto_surround = auto_surround;
 2850    }
 2851
 2852    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2853        self.auto_replace_emoji_shortcode = auto_replace;
 2854    }
 2855
 2856    pub fn toggle_edit_predictions(
 2857        &mut self,
 2858        _: &ToggleEditPrediction,
 2859        window: &mut Window,
 2860        cx: &mut Context<Self>,
 2861    ) {
 2862        if self.show_inline_completions_override.is_some() {
 2863            self.set_show_edit_predictions(None, window, cx);
 2864        } else {
 2865            let show_edit_predictions = !self.edit_predictions_enabled();
 2866            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2867        }
 2868    }
 2869
 2870    pub fn set_show_edit_predictions(
 2871        &mut self,
 2872        show_edit_predictions: Option<bool>,
 2873        window: &mut Window,
 2874        cx: &mut Context<Self>,
 2875    ) {
 2876        self.show_inline_completions_override = show_edit_predictions;
 2877        self.update_edit_prediction_settings(cx);
 2878
 2879        if let Some(false) = show_edit_predictions {
 2880            self.discard_inline_completion(false, cx);
 2881        } else {
 2882            self.refresh_inline_completion(false, true, window, cx);
 2883        }
 2884    }
 2885
 2886    fn inline_completions_disabled_in_scope(
 2887        &self,
 2888        buffer: &Entity<Buffer>,
 2889        buffer_position: language::Anchor,
 2890        cx: &App,
 2891    ) -> bool {
 2892        let snapshot = buffer.read(cx).snapshot();
 2893        let settings = snapshot.settings_at(buffer_position, cx);
 2894
 2895        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2896            return false;
 2897        };
 2898
 2899        scope.override_name().map_or(false, |scope_name| {
 2900            settings
 2901                .edit_predictions_disabled_in
 2902                .iter()
 2903                .any(|s| s == scope_name)
 2904        })
 2905    }
 2906
 2907    pub fn set_use_modal_editing(&mut self, to: bool) {
 2908        self.use_modal_editing = to;
 2909    }
 2910
 2911    pub fn use_modal_editing(&self) -> bool {
 2912        self.use_modal_editing
 2913    }
 2914
 2915    fn selections_did_change(
 2916        &mut self,
 2917        local: bool,
 2918        old_cursor_position: &Anchor,
 2919        effects: SelectionEffects,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        window.invalidate_character_coordinates();
 2924
 2925        // Copy selections to primary selection buffer
 2926        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2927        if local {
 2928            let selections = self.selections.all::<usize>(cx);
 2929            let buffer_handle = self.buffer.read(cx).read(cx);
 2930
 2931            let mut text = String::new();
 2932            for (index, selection) in selections.iter().enumerate() {
 2933                let text_for_selection = buffer_handle
 2934                    .text_for_range(selection.start..selection.end)
 2935                    .collect::<String>();
 2936
 2937                text.push_str(&text_for_selection);
 2938                if index != selections.len() - 1 {
 2939                    text.push('\n');
 2940                }
 2941            }
 2942
 2943            if !text.is_empty() {
 2944                cx.write_to_primary(ClipboardItem::new_string(text));
 2945            }
 2946        }
 2947
 2948        let selection_anchors = self.selections.disjoint_anchors();
 2949
 2950        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2951            self.buffer.update(cx, |buffer, cx| {
 2952                buffer.set_active_selections(
 2953                    &selection_anchors,
 2954                    self.selections.line_mode,
 2955                    self.cursor_shape,
 2956                    cx,
 2957                )
 2958            });
 2959        }
 2960        let display_map = self
 2961            .display_map
 2962            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2963        let buffer = &display_map.buffer_snapshot;
 2964        if self.selections.count() == 1 {
 2965            self.add_selections_state = None;
 2966        }
 2967        self.select_next_state = None;
 2968        self.select_prev_state = None;
 2969        self.select_syntax_node_history.try_clear();
 2970        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2971        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2972        self.take_rename(false, window, cx);
 2973
 2974        let newest_selection = self.selections.newest_anchor();
 2975        let new_cursor_position = newest_selection.head();
 2976        let selection_start = newest_selection.start;
 2977
 2978        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2979            self.push_to_nav_history(
 2980                *old_cursor_position,
 2981                Some(new_cursor_position.to_point(buffer)),
 2982                false,
 2983                effects.nav_history == Some(true),
 2984                cx,
 2985            );
 2986        }
 2987
 2988        if local {
 2989            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2990                if !self.registered_buffers.contains_key(&buffer_id) {
 2991                    if let Some(project) = self.project.as_ref() {
 2992                        project.update(cx, |project, cx| {
 2993                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2994                                return;
 2995                            };
 2996                            self.registered_buffers.insert(
 2997                                buffer_id,
 2998                                project.register_buffer_with_language_servers(&buffer, cx),
 2999                            );
 3000                        })
 3001                    }
 3002                }
 3003            }
 3004
 3005            let mut context_menu = self.context_menu.borrow_mut();
 3006            let completion_menu = match context_menu.as_ref() {
 3007                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3008                Some(CodeContextMenu::CodeActions(_)) => {
 3009                    *context_menu = None;
 3010                    None
 3011                }
 3012                None => None,
 3013            };
 3014            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3015            drop(context_menu);
 3016
 3017            if effects.completions {
 3018                if let Some(completion_position) = completion_position {
 3019                    let start_offset = selection_start.to_offset(buffer);
 3020                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3021                    let continue_showing = if position_matches {
 3022                        if self.snippet_stack.is_empty() {
 3023                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3024                        } else {
 3025                            // Snippet choices can be shown even when the cursor is in whitespace.
 3026                            // Dismissing the menu with actions like backspace is handled by
 3027                            // invalidation regions.
 3028                            true
 3029                        }
 3030                    } else {
 3031                        false
 3032                    };
 3033
 3034                    if continue_showing {
 3035                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3036                    } else {
 3037                        self.hide_context_menu(window, cx);
 3038                    }
 3039                }
 3040            }
 3041
 3042            hide_hover(self, cx);
 3043
 3044            if old_cursor_position.to_display_point(&display_map).row()
 3045                != new_cursor_position.to_display_point(&display_map).row()
 3046            {
 3047                self.available_code_actions.take();
 3048            }
 3049            self.refresh_code_actions(window, cx);
 3050            self.refresh_document_highlights(cx);
 3051            self.refresh_selected_text_highlights(false, window, cx);
 3052            refresh_matching_bracket_highlights(self, window, cx);
 3053            self.update_visible_inline_completion(window, cx);
 3054            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3055            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3056            self.inline_blame_popover.take();
 3057            if self.git_blame_inline_enabled {
 3058                self.start_inline_blame_timer(window, cx);
 3059            }
 3060        }
 3061
 3062        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3063        cx.emit(EditorEvent::SelectionsChanged { local });
 3064
 3065        let selections = &self.selections.disjoint;
 3066        if selections.len() == 1 {
 3067            cx.emit(SearchEvent::ActiveMatchChanged)
 3068        }
 3069        if local {
 3070            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3071                let inmemory_selections = selections
 3072                    .iter()
 3073                    .map(|s| {
 3074                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3075                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3076                    })
 3077                    .collect();
 3078                self.update_restoration_data(cx, |data| {
 3079                    data.selections = inmemory_selections;
 3080                });
 3081
 3082                if WorkspaceSettings::get(None, cx).restore_on_startup
 3083                    != RestoreOnStartupBehavior::None
 3084                {
 3085                    if let Some(workspace_id) =
 3086                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3087                    {
 3088                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3089                        let selections = selections.clone();
 3090                        let background_executor = cx.background_executor().clone();
 3091                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3092                        self.serialize_selections = cx.background_spawn(async move {
 3093                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3094                            let db_selections = selections
 3095                                .iter()
 3096                                .map(|selection| {
 3097                                    (
 3098                                        selection.start.to_offset(&snapshot),
 3099                                        selection.end.to_offset(&snapshot),
 3100                                    )
 3101                                })
 3102                                .collect();
 3103
 3104                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3105                                .await
 3106                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3107                                .log_err();
 3108                        });
 3109                    }
 3110                }
 3111            }
 3112        }
 3113
 3114        cx.notify();
 3115    }
 3116
 3117    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3118        use text::ToOffset as _;
 3119        use text::ToPoint as _;
 3120
 3121        if self.mode.is_minimap()
 3122            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3123        {
 3124            return;
 3125        }
 3126
 3127        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3128            return;
 3129        };
 3130
 3131        let snapshot = singleton.read(cx).snapshot();
 3132        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3133            let display_snapshot = display_map.snapshot(cx);
 3134
 3135            display_snapshot
 3136                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3137                .map(|fold| {
 3138                    fold.range.start.text_anchor.to_point(&snapshot)
 3139                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3140                })
 3141                .collect()
 3142        });
 3143        self.update_restoration_data(cx, |data| {
 3144            data.folds = inmemory_folds;
 3145        });
 3146
 3147        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3148            return;
 3149        };
 3150        let background_executor = cx.background_executor().clone();
 3151        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3152        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3153            display_map
 3154                .snapshot(cx)
 3155                .folds_in_range(0..snapshot.len())
 3156                .map(|fold| {
 3157                    (
 3158                        fold.range.start.text_anchor.to_offset(&snapshot),
 3159                        fold.range.end.text_anchor.to_offset(&snapshot),
 3160                    )
 3161                })
 3162                .collect()
 3163        });
 3164        self.serialize_folds = cx.background_spawn(async move {
 3165            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3166            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3167                .await
 3168                .with_context(|| {
 3169                    format!(
 3170                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3171                    )
 3172                })
 3173                .log_err();
 3174        });
 3175    }
 3176
 3177    pub fn sync_selections(
 3178        &mut self,
 3179        other: Entity<Editor>,
 3180        cx: &mut Context<Self>,
 3181    ) -> gpui::Subscription {
 3182        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3183        self.selections.change_with(cx, |selections| {
 3184            selections.select_anchors(other_selections);
 3185        });
 3186
 3187        let other_subscription =
 3188            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3189                EditorEvent::SelectionsChanged { local: true } => {
 3190                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3191                    if other_selections.is_empty() {
 3192                        return;
 3193                    }
 3194                    this.selections.change_with(cx, |selections| {
 3195                        selections.select_anchors(other_selections);
 3196                    });
 3197                }
 3198                _ => {}
 3199            });
 3200
 3201        let this_subscription =
 3202            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3203                EditorEvent::SelectionsChanged { local: true } => {
 3204                    let these_selections = this.selections.disjoint.to_vec();
 3205                    if these_selections.is_empty() {
 3206                        return;
 3207                    }
 3208                    other.update(cx, |other_editor, cx| {
 3209                        other_editor.selections.change_with(cx, |selections| {
 3210                            selections.select_anchors(these_selections);
 3211                        })
 3212                    });
 3213                }
 3214                _ => {}
 3215            });
 3216
 3217        Subscription::join(other_subscription, this_subscription)
 3218    }
 3219
 3220    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3221    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3222    /// effects of selection change occur at the end of the transaction.
 3223    pub fn change_selections<R>(
 3224        &mut self,
 3225        effects: SelectionEffects,
 3226        window: &mut Window,
 3227        cx: &mut Context<Self>,
 3228        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3229    ) -> R {
 3230        if let Some(state) = &mut self.deferred_selection_effects_state {
 3231            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3232            state.effects.completions = effects.completions;
 3233            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3234            let (changed, result) = self.selections.change_with(cx, change);
 3235            state.changed |= changed;
 3236            return result;
 3237        }
 3238        let mut state = DeferredSelectionEffectsState {
 3239            changed: false,
 3240            effects,
 3241            old_cursor_position: self.selections.newest_anchor().head(),
 3242            history_entry: SelectionHistoryEntry {
 3243                selections: self.selections.disjoint_anchors(),
 3244                select_next_state: self.select_next_state.clone(),
 3245                select_prev_state: self.select_prev_state.clone(),
 3246                add_selections_state: self.add_selections_state.clone(),
 3247            },
 3248        };
 3249        let (changed, result) = self.selections.change_with(cx, change);
 3250        state.changed = state.changed || changed;
 3251        if self.defer_selection_effects {
 3252            self.deferred_selection_effects_state = Some(state);
 3253        } else {
 3254            self.apply_selection_effects(state, window, cx);
 3255        }
 3256        result
 3257    }
 3258
 3259    /// Defers the effects of selection change, so that the effects of multiple calls to
 3260    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3261    /// to selection history and the state of popovers based on selection position aren't
 3262    /// erroneously updated.
 3263    pub fn with_selection_effects_deferred<R>(
 3264        &mut self,
 3265        window: &mut Window,
 3266        cx: &mut Context<Self>,
 3267        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3268    ) -> R {
 3269        let already_deferred = self.defer_selection_effects;
 3270        self.defer_selection_effects = true;
 3271        let result = update(self, window, cx);
 3272        if !already_deferred {
 3273            self.defer_selection_effects = false;
 3274            if let Some(state) = self.deferred_selection_effects_state.take() {
 3275                self.apply_selection_effects(state, window, cx);
 3276            }
 3277        }
 3278        result
 3279    }
 3280
 3281    fn apply_selection_effects(
 3282        &mut self,
 3283        state: DeferredSelectionEffectsState,
 3284        window: &mut Window,
 3285        cx: &mut Context<Self>,
 3286    ) {
 3287        if state.changed {
 3288            self.selection_history.push(state.history_entry);
 3289
 3290            if let Some(autoscroll) = state.effects.scroll {
 3291                self.request_autoscroll(autoscroll, cx);
 3292            }
 3293
 3294            let old_cursor_position = &state.old_cursor_position;
 3295
 3296            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3297
 3298            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3299                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3300            }
 3301        }
 3302    }
 3303
 3304    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3305    where
 3306        I: IntoIterator<Item = (Range<S>, T)>,
 3307        S: ToOffset,
 3308        T: Into<Arc<str>>,
 3309    {
 3310        if self.read_only(cx) {
 3311            return;
 3312        }
 3313
 3314        self.buffer
 3315            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3316    }
 3317
 3318    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3319    where
 3320        I: IntoIterator<Item = (Range<S>, T)>,
 3321        S: ToOffset,
 3322        T: Into<Arc<str>>,
 3323    {
 3324        if self.read_only(cx) {
 3325            return;
 3326        }
 3327
 3328        self.buffer.update(cx, |buffer, cx| {
 3329            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3330        });
 3331    }
 3332
 3333    pub fn edit_with_block_indent<I, S, T>(
 3334        &mut self,
 3335        edits: I,
 3336        original_indent_columns: Vec<Option<u32>>,
 3337        cx: &mut Context<Self>,
 3338    ) where
 3339        I: IntoIterator<Item = (Range<S>, T)>,
 3340        S: ToOffset,
 3341        T: Into<Arc<str>>,
 3342    {
 3343        if self.read_only(cx) {
 3344            return;
 3345        }
 3346
 3347        self.buffer.update(cx, |buffer, cx| {
 3348            buffer.edit(
 3349                edits,
 3350                Some(AutoindentMode::Block {
 3351                    original_indent_columns,
 3352                }),
 3353                cx,
 3354            )
 3355        });
 3356    }
 3357
 3358    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3359        self.hide_context_menu(window, cx);
 3360
 3361        match phase {
 3362            SelectPhase::Begin {
 3363                position,
 3364                add,
 3365                click_count,
 3366            } => self.begin_selection(position, add, click_count, window, cx),
 3367            SelectPhase::BeginColumnar {
 3368                position,
 3369                goal_column,
 3370                reset,
 3371                mode,
 3372            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3373            SelectPhase::Extend {
 3374                position,
 3375                click_count,
 3376            } => self.extend_selection(position, click_count, window, cx),
 3377            SelectPhase::Update {
 3378                position,
 3379                goal_column,
 3380                scroll_delta,
 3381            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3382            SelectPhase::End => self.end_selection(window, cx),
 3383        }
 3384    }
 3385
 3386    fn extend_selection(
 3387        &mut self,
 3388        position: DisplayPoint,
 3389        click_count: usize,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3394        let tail = self.selections.newest::<usize>(cx).tail();
 3395        self.begin_selection(position, false, click_count, window, cx);
 3396
 3397        let position = position.to_offset(&display_map, Bias::Left);
 3398        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3399
 3400        let mut pending_selection = self
 3401            .selections
 3402            .pending_anchor()
 3403            .expect("extend_selection not called with pending selection");
 3404        if position >= tail {
 3405            pending_selection.start = tail_anchor;
 3406        } else {
 3407            pending_selection.end = tail_anchor;
 3408            pending_selection.reversed = true;
 3409        }
 3410
 3411        let mut pending_mode = self.selections.pending_mode().unwrap();
 3412        match &mut pending_mode {
 3413            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3414            _ => {}
 3415        }
 3416
 3417        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3418            SelectionEffects::scroll(Autoscroll::fit())
 3419        } else {
 3420            SelectionEffects::no_scroll()
 3421        };
 3422
 3423        self.change_selections(effects, window, cx, |s| {
 3424            s.set_pending(pending_selection, pending_mode)
 3425        });
 3426    }
 3427
 3428    fn begin_selection(
 3429        &mut self,
 3430        position: DisplayPoint,
 3431        add: bool,
 3432        click_count: usize,
 3433        window: &mut Window,
 3434        cx: &mut Context<Self>,
 3435    ) {
 3436        if !self.focus_handle.is_focused(window) {
 3437            self.last_focused_descendant = None;
 3438            window.focus(&self.focus_handle);
 3439        }
 3440
 3441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3442        let buffer = &display_map.buffer_snapshot;
 3443        let position = display_map.clip_point(position, Bias::Left);
 3444
 3445        let start;
 3446        let end;
 3447        let mode;
 3448        let mut auto_scroll;
 3449        match click_count {
 3450            1 => {
 3451                start = buffer.anchor_before(position.to_point(&display_map));
 3452                end = start;
 3453                mode = SelectMode::Character;
 3454                auto_scroll = true;
 3455            }
 3456            2 => {
 3457                let position = display_map
 3458                    .clip_point(position, Bias::Left)
 3459                    .to_offset(&display_map, Bias::Left);
 3460                let (range, _) = buffer.surrounding_word(position, false);
 3461                start = buffer.anchor_before(range.start);
 3462                end = buffer.anchor_before(range.end);
 3463                mode = SelectMode::Word(start..end);
 3464                auto_scroll = true;
 3465            }
 3466            3 => {
 3467                let position = display_map
 3468                    .clip_point(position, Bias::Left)
 3469                    .to_point(&display_map);
 3470                let line_start = display_map.prev_line_boundary(position).0;
 3471                let next_line_start = buffer.clip_point(
 3472                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3473                    Bias::Left,
 3474                );
 3475                start = buffer.anchor_before(line_start);
 3476                end = buffer.anchor_before(next_line_start);
 3477                mode = SelectMode::Line(start..end);
 3478                auto_scroll = true;
 3479            }
 3480            _ => {
 3481                start = buffer.anchor_before(0);
 3482                end = buffer.anchor_before(buffer.len());
 3483                mode = SelectMode::All;
 3484                auto_scroll = false;
 3485            }
 3486        }
 3487        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3488
 3489        let point_to_delete: Option<usize> = {
 3490            let selected_points: Vec<Selection<Point>> =
 3491                self.selections.disjoint_in_range(start..end, cx);
 3492
 3493            if !add || click_count > 1 {
 3494                None
 3495            } else if !selected_points.is_empty() {
 3496                Some(selected_points[0].id)
 3497            } else {
 3498                let clicked_point_already_selected =
 3499                    self.selections.disjoint.iter().find(|selection| {
 3500                        selection.start.to_point(buffer) == start.to_point(buffer)
 3501                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3502                    });
 3503
 3504                clicked_point_already_selected.map(|selection| selection.id)
 3505            }
 3506        };
 3507
 3508        let selections_count = self.selections.count();
 3509        let effects = if auto_scroll {
 3510            SelectionEffects::default()
 3511        } else {
 3512            SelectionEffects::no_scroll()
 3513        };
 3514
 3515        self.change_selections(effects, window, cx, |s| {
 3516            if let Some(point_to_delete) = point_to_delete {
 3517                s.delete(point_to_delete);
 3518
 3519                if selections_count == 1 {
 3520                    s.set_pending_anchor_range(start..end, mode);
 3521                }
 3522            } else {
 3523                if !add {
 3524                    s.clear_disjoint();
 3525                }
 3526
 3527                s.set_pending_anchor_range(start..end, mode);
 3528            }
 3529        });
 3530    }
 3531
 3532    fn begin_columnar_selection(
 3533        &mut self,
 3534        position: DisplayPoint,
 3535        goal_column: u32,
 3536        reset: bool,
 3537        mode: ColumnarMode,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) {
 3541        if !self.focus_handle.is_focused(window) {
 3542            self.last_focused_descendant = None;
 3543            window.focus(&self.focus_handle);
 3544        }
 3545
 3546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3547
 3548        if reset {
 3549            let pointer_position = display_map
 3550                .buffer_snapshot
 3551                .anchor_before(position.to_point(&display_map));
 3552
 3553            self.change_selections(
 3554                SelectionEffects::scroll(Autoscroll::newest()),
 3555                window,
 3556                cx,
 3557                |s| {
 3558                    s.clear_disjoint();
 3559                    s.set_pending_anchor_range(
 3560                        pointer_position..pointer_position,
 3561                        SelectMode::Character,
 3562                    );
 3563                },
 3564            );
 3565        };
 3566
 3567        let tail = self.selections.newest::<Point>(cx).tail();
 3568        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3569        self.columnar_selection_state = match mode {
 3570            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3571                selection_tail: selection_anchor,
 3572                display_point: if reset {
 3573                    if position.column() != goal_column {
 3574                        Some(DisplayPoint::new(position.row(), goal_column))
 3575                    } else {
 3576                        None
 3577                    }
 3578                } else {
 3579                    None
 3580                },
 3581            }),
 3582            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3583                selection_tail: selection_anchor,
 3584            }),
 3585        };
 3586
 3587        if !reset {
 3588            self.select_columns(position, goal_column, &display_map, window, cx);
 3589        }
 3590    }
 3591
 3592    fn update_selection(
 3593        &mut self,
 3594        position: DisplayPoint,
 3595        goal_column: u32,
 3596        scroll_delta: gpui::Point<f32>,
 3597        window: &mut Window,
 3598        cx: &mut Context<Self>,
 3599    ) {
 3600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3601
 3602        if self.columnar_selection_state.is_some() {
 3603            self.select_columns(position, goal_column, &display_map, window, cx);
 3604        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3605            let buffer = &display_map.buffer_snapshot;
 3606            let head;
 3607            let tail;
 3608            let mode = self.selections.pending_mode().unwrap();
 3609            match &mode {
 3610                SelectMode::Character => {
 3611                    head = position.to_point(&display_map);
 3612                    tail = pending.tail().to_point(buffer);
 3613                }
 3614                SelectMode::Word(original_range) => {
 3615                    let offset = display_map
 3616                        .clip_point(position, Bias::Left)
 3617                        .to_offset(&display_map, Bias::Left);
 3618                    let original_range = original_range.to_offset(buffer);
 3619
 3620                    let head_offset = if buffer.is_inside_word(offset, false)
 3621                        || original_range.contains(&offset)
 3622                    {
 3623                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3624                        if word_range.start < original_range.start {
 3625                            word_range.start
 3626                        } else {
 3627                            word_range.end
 3628                        }
 3629                    } else {
 3630                        offset
 3631                    };
 3632
 3633                    head = head_offset.to_point(buffer);
 3634                    if head_offset <= original_range.start {
 3635                        tail = original_range.end.to_point(buffer);
 3636                    } else {
 3637                        tail = original_range.start.to_point(buffer);
 3638                    }
 3639                }
 3640                SelectMode::Line(original_range) => {
 3641                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3642
 3643                    let position = display_map
 3644                        .clip_point(position, Bias::Left)
 3645                        .to_point(&display_map);
 3646                    let line_start = display_map.prev_line_boundary(position).0;
 3647                    let next_line_start = buffer.clip_point(
 3648                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3649                        Bias::Left,
 3650                    );
 3651
 3652                    if line_start < original_range.start {
 3653                        head = line_start
 3654                    } else {
 3655                        head = next_line_start
 3656                    }
 3657
 3658                    if head <= original_range.start {
 3659                        tail = original_range.end;
 3660                    } else {
 3661                        tail = original_range.start;
 3662                    }
 3663                }
 3664                SelectMode::All => {
 3665                    return;
 3666                }
 3667            };
 3668
 3669            if head < tail {
 3670                pending.start = buffer.anchor_before(head);
 3671                pending.end = buffer.anchor_before(tail);
 3672                pending.reversed = true;
 3673            } else {
 3674                pending.start = buffer.anchor_before(tail);
 3675                pending.end = buffer.anchor_before(head);
 3676                pending.reversed = false;
 3677            }
 3678
 3679            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3680                s.set_pending(pending, mode);
 3681            });
 3682        } else {
 3683            log::error!("update_selection dispatched with no pending selection");
 3684            return;
 3685        }
 3686
 3687        self.apply_scroll_delta(scroll_delta, window, cx);
 3688        cx.notify();
 3689    }
 3690
 3691    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3692        self.columnar_selection_state.take();
 3693        if self.selections.pending_anchor().is_some() {
 3694            let selections = self.selections.all::<usize>(cx);
 3695            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3696                s.select(selections);
 3697                s.clear_pending();
 3698            });
 3699        }
 3700    }
 3701
 3702    fn select_columns(
 3703        &mut self,
 3704        head: DisplayPoint,
 3705        goal_column: u32,
 3706        display_map: &DisplaySnapshot,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3711            return;
 3712        };
 3713
 3714        let tail = match columnar_state {
 3715            ColumnarSelectionState::FromMouse {
 3716                selection_tail,
 3717                display_point,
 3718            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3719            ColumnarSelectionState::FromSelection { selection_tail } => {
 3720                selection_tail.to_display_point(&display_map)
 3721            }
 3722        };
 3723
 3724        let start_row = cmp::min(tail.row(), head.row());
 3725        let end_row = cmp::max(tail.row(), head.row());
 3726        let start_column = cmp::min(tail.column(), goal_column);
 3727        let end_column = cmp::max(tail.column(), goal_column);
 3728        let reversed = start_column < tail.column();
 3729
 3730        let selection_ranges = (start_row.0..=end_row.0)
 3731            .map(DisplayRow)
 3732            .filter_map(|row| {
 3733                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3734                    || start_column <= display_map.line_len(row))
 3735                    && !display_map.is_block_line(row)
 3736                {
 3737                    let start = display_map
 3738                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3739                        .to_point(display_map);
 3740                    let end = display_map
 3741                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3742                        .to_point(display_map);
 3743                    if reversed {
 3744                        Some(end..start)
 3745                    } else {
 3746                        Some(start..end)
 3747                    }
 3748                } else {
 3749                    None
 3750                }
 3751            })
 3752            .collect::<Vec<_>>();
 3753
 3754        let ranges = match columnar_state {
 3755            ColumnarSelectionState::FromMouse { .. } => {
 3756                let mut non_empty_ranges = selection_ranges
 3757                    .iter()
 3758                    .filter(|selection_range| selection_range.start != selection_range.end)
 3759                    .peekable();
 3760                if non_empty_ranges.peek().is_some() {
 3761                    non_empty_ranges.cloned().collect()
 3762                } else {
 3763                    selection_ranges
 3764                }
 3765            }
 3766            _ => selection_ranges,
 3767        };
 3768
 3769        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3770            s.select_ranges(ranges);
 3771        });
 3772        cx.notify();
 3773    }
 3774
 3775    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3776        self.selections
 3777            .all_adjusted(cx)
 3778            .iter()
 3779            .any(|selection| !selection.is_empty())
 3780    }
 3781
 3782    pub fn has_pending_nonempty_selection(&self) -> bool {
 3783        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3784            Some(Selection { start, end, .. }) => start != end,
 3785            None => false,
 3786        };
 3787
 3788        pending_nonempty_selection
 3789            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3790    }
 3791
 3792    pub fn has_pending_selection(&self) -> bool {
 3793        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3794    }
 3795
 3796    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3797        self.selection_mark_mode = false;
 3798        self.selection_drag_state = SelectionDragState::None;
 3799
 3800        if self.clear_expanded_diff_hunks(cx) {
 3801            cx.notify();
 3802            return;
 3803        }
 3804        if self.dismiss_menus_and_popups(true, window, cx) {
 3805            return;
 3806        }
 3807
 3808        if self.mode.is_full()
 3809            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3810        {
 3811            return;
 3812        }
 3813
 3814        cx.propagate();
 3815    }
 3816
 3817    pub fn dismiss_menus_and_popups(
 3818        &mut self,
 3819        is_user_requested: bool,
 3820        window: &mut Window,
 3821        cx: &mut Context<Self>,
 3822    ) -> bool {
 3823        if self.take_rename(false, window, cx).is_some() {
 3824            return true;
 3825        }
 3826
 3827        if hide_hover(self, cx) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3832            return true;
 3833        }
 3834
 3835        if self.hide_context_menu(window, cx).is_some() {
 3836            return true;
 3837        }
 3838
 3839        if self.mouse_context_menu.take().is_some() {
 3840            return true;
 3841        }
 3842
 3843        if is_user_requested && self.discard_inline_completion(true, cx) {
 3844            return true;
 3845        }
 3846
 3847        if self.snippet_stack.pop().is_some() {
 3848            return true;
 3849        }
 3850
 3851        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3852            self.dismiss_diagnostics(cx);
 3853            return true;
 3854        }
 3855
 3856        false
 3857    }
 3858
 3859    fn linked_editing_ranges_for(
 3860        &self,
 3861        selection: Range<text::Anchor>,
 3862        cx: &App,
 3863    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3864        if self.linked_edit_ranges.is_empty() {
 3865            return None;
 3866        }
 3867        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3868            selection.end.buffer_id.and_then(|end_buffer_id| {
 3869                if selection.start.buffer_id != Some(end_buffer_id) {
 3870                    return None;
 3871                }
 3872                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3873                let snapshot = buffer.read(cx).snapshot();
 3874                self.linked_edit_ranges
 3875                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3876                    .map(|ranges| (ranges, snapshot, buffer))
 3877            })?;
 3878        use text::ToOffset as TO;
 3879        // find offset from the start of current range to current cursor position
 3880        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3881
 3882        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3883        let start_difference = start_offset - start_byte_offset;
 3884        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3885        let end_difference = end_offset - start_byte_offset;
 3886        // Current range has associated linked ranges.
 3887        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3888        for range in linked_ranges.iter() {
 3889            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3890            let end_offset = start_offset + end_difference;
 3891            let start_offset = start_offset + start_difference;
 3892            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3893                continue;
 3894            }
 3895            if self.selections.disjoint_anchor_ranges().any(|s| {
 3896                if s.start.buffer_id != selection.start.buffer_id
 3897                    || s.end.buffer_id != selection.end.buffer_id
 3898                {
 3899                    return false;
 3900                }
 3901                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3902                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3903            }) {
 3904                continue;
 3905            }
 3906            let start = buffer_snapshot.anchor_after(start_offset);
 3907            let end = buffer_snapshot.anchor_after(end_offset);
 3908            linked_edits
 3909                .entry(buffer.clone())
 3910                .or_default()
 3911                .push(start..end);
 3912        }
 3913        Some(linked_edits)
 3914    }
 3915
 3916    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3917        let text: Arc<str> = text.into();
 3918
 3919        if self.read_only(cx) {
 3920            return;
 3921        }
 3922
 3923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3924
 3925        let selections = self.selections.all_adjusted(cx);
 3926        let mut bracket_inserted = false;
 3927        let mut edits = Vec::new();
 3928        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3929        let mut new_selections = Vec::with_capacity(selections.len());
 3930        let mut new_autoclose_regions = Vec::new();
 3931        let snapshot = self.buffer.read(cx).read(cx);
 3932        let mut clear_linked_edit_ranges = false;
 3933
 3934        for (selection, autoclose_region) in
 3935            self.selections_with_autoclose_regions(selections, &snapshot)
 3936        {
 3937            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3938                // Determine if the inserted text matches the opening or closing
 3939                // bracket of any of this language's bracket pairs.
 3940                let mut bracket_pair = None;
 3941                let mut is_bracket_pair_start = false;
 3942                let mut is_bracket_pair_end = false;
 3943                if !text.is_empty() {
 3944                    let mut bracket_pair_matching_end = None;
 3945                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3946                    //  and they are removing the character that triggered IME popup.
 3947                    for (pair, enabled) in scope.brackets() {
 3948                        if !pair.close && !pair.surround {
 3949                            continue;
 3950                        }
 3951
 3952                        if enabled && pair.start.ends_with(text.as_ref()) {
 3953                            let prefix_len = pair.start.len() - text.len();
 3954                            let preceding_text_matches_prefix = prefix_len == 0
 3955                                || (selection.start.column >= (prefix_len as u32)
 3956                                    && snapshot.contains_str_at(
 3957                                        Point::new(
 3958                                            selection.start.row,
 3959                                            selection.start.column - (prefix_len as u32),
 3960                                        ),
 3961                                        &pair.start[..prefix_len],
 3962                                    ));
 3963                            if preceding_text_matches_prefix {
 3964                                bracket_pair = Some(pair.clone());
 3965                                is_bracket_pair_start = true;
 3966                                break;
 3967                            }
 3968                        }
 3969                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3970                        {
 3971                            // take first bracket pair matching end, but don't break in case a later bracket
 3972                            // pair matches start
 3973                            bracket_pair_matching_end = Some(pair.clone());
 3974                        }
 3975                    }
 3976                    if let Some(end) = bracket_pair_matching_end
 3977                        && bracket_pair.is_none()
 3978                    {
 3979                        bracket_pair = Some(end);
 3980                        is_bracket_pair_end = true;
 3981                    }
 3982                }
 3983
 3984                if let Some(bracket_pair) = bracket_pair {
 3985                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3986                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3987                    let auto_surround =
 3988                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3989                    if selection.is_empty() {
 3990                        if is_bracket_pair_start {
 3991                            // If the inserted text is a suffix of an opening bracket and the
 3992                            // selection is preceded by the rest of the opening bracket, then
 3993                            // insert the closing bracket.
 3994                            let following_text_allows_autoclose = snapshot
 3995                                .chars_at(selection.start)
 3996                                .next()
 3997                                .map_or(true, |c| scope.should_autoclose_before(c));
 3998
 3999                            let preceding_text_allows_autoclose = selection.start.column == 0
 4000                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4001                                    true,
 4002                                    |c| {
 4003                                        bracket_pair.start != bracket_pair.end
 4004                                            || !snapshot
 4005                                                .char_classifier_at(selection.start)
 4006                                                .is_word(c)
 4007                                    },
 4008                                );
 4009
 4010                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4011                                && bracket_pair.start.len() == 1
 4012                            {
 4013                                let target = bracket_pair.start.chars().next().unwrap();
 4014                                let current_line_count = snapshot
 4015                                    .reversed_chars_at(selection.start)
 4016                                    .take_while(|&c| c != '\n')
 4017                                    .filter(|&c| c == target)
 4018                                    .count();
 4019                                current_line_count % 2 == 1
 4020                            } else {
 4021                                false
 4022                            };
 4023
 4024                            if autoclose
 4025                                && bracket_pair.close
 4026                                && following_text_allows_autoclose
 4027                                && preceding_text_allows_autoclose
 4028                                && !is_closing_quote
 4029                            {
 4030                                let anchor = snapshot.anchor_before(selection.end);
 4031                                new_selections.push((selection.map(|_| anchor), text.len()));
 4032                                new_autoclose_regions.push((
 4033                                    anchor,
 4034                                    text.len(),
 4035                                    selection.id,
 4036                                    bracket_pair.clone(),
 4037                                ));
 4038                                edits.push((
 4039                                    selection.range(),
 4040                                    format!("{}{}", text, bracket_pair.end).into(),
 4041                                ));
 4042                                bracket_inserted = true;
 4043                                continue;
 4044                            }
 4045                        }
 4046
 4047                        if let Some(region) = autoclose_region {
 4048                            // If the selection is followed by an auto-inserted closing bracket,
 4049                            // then don't insert that closing bracket again; just move the selection
 4050                            // past the closing bracket.
 4051                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4052                                && text.as_ref() == region.pair.end.as_str()
 4053                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4054                            if should_skip {
 4055                                let anchor = snapshot.anchor_after(selection.end);
 4056                                new_selections
 4057                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4058                                continue;
 4059                            }
 4060                        }
 4061
 4062                        let always_treat_brackets_as_autoclosed = snapshot
 4063                            .language_settings_at(selection.start, cx)
 4064                            .always_treat_brackets_as_autoclosed;
 4065                        if always_treat_brackets_as_autoclosed
 4066                            && is_bracket_pair_end
 4067                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4068                        {
 4069                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4070                            // and the inserted text is a closing bracket and the selection is followed
 4071                            // by the closing bracket then move the selection past the closing bracket.
 4072                            let anchor = snapshot.anchor_after(selection.end);
 4073                            new_selections.push((selection.map(|_| anchor), text.len()));
 4074                            continue;
 4075                        }
 4076                    }
 4077                    // If an opening bracket is 1 character long and is typed while
 4078                    // text is selected, then surround that text with the bracket pair.
 4079                    else if auto_surround
 4080                        && bracket_pair.surround
 4081                        && is_bracket_pair_start
 4082                        && bracket_pair.start.chars().count() == 1
 4083                    {
 4084                        edits.push((selection.start..selection.start, text.clone()));
 4085                        edits.push((
 4086                            selection.end..selection.end,
 4087                            bracket_pair.end.as_str().into(),
 4088                        ));
 4089                        bracket_inserted = true;
 4090                        new_selections.push((
 4091                            Selection {
 4092                                id: selection.id,
 4093                                start: snapshot.anchor_after(selection.start),
 4094                                end: snapshot.anchor_before(selection.end),
 4095                                reversed: selection.reversed,
 4096                                goal: selection.goal,
 4097                            },
 4098                            0,
 4099                        ));
 4100                        continue;
 4101                    }
 4102                }
 4103            }
 4104
 4105            if self.auto_replace_emoji_shortcode
 4106                && selection.is_empty()
 4107                && text.as_ref().ends_with(':')
 4108            {
 4109                if let Some(possible_emoji_short_code) =
 4110                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4111                {
 4112                    if !possible_emoji_short_code.is_empty() {
 4113                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4114                            let emoji_shortcode_start = Point::new(
 4115                                selection.start.row,
 4116                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4117                            );
 4118
 4119                            // Remove shortcode from buffer
 4120                            edits.push((
 4121                                emoji_shortcode_start..selection.start,
 4122                                "".to_string().into(),
 4123                            ));
 4124                            new_selections.push((
 4125                                Selection {
 4126                                    id: selection.id,
 4127                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4128                                    end: snapshot.anchor_before(selection.start),
 4129                                    reversed: selection.reversed,
 4130                                    goal: selection.goal,
 4131                                },
 4132                                0,
 4133                            ));
 4134
 4135                            // Insert emoji
 4136                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4137                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4138                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4139
 4140                            continue;
 4141                        }
 4142                    }
 4143                }
 4144            }
 4145
 4146            // If not handling any auto-close operation, then just replace the selected
 4147            // text with the given input and move the selection to the end of the
 4148            // newly inserted text.
 4149            let anchor = snapshot.anchor_after(selection.end);
 4150            if !self.linked_edit_ranges.is_empty() {
 4151                let start_anchor = snapshot.anchor_before(selection.start);
 4152
 4153                let is_word_char = text.chars().next().map_or(true, |char| {
 4154                    let classifier = snapshot
 4155                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4156                        .ignore_punctuation(true);
 4157                    classifier.is_word(char)
 4158                });
 4159
 4160                if is_word_char {
 4161                    if let Some(ranges) = self
 4162                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4163                    {
 4164                        for (buffer, edits) in ranges {
 4165                            linked_edits
 4166                                .entry(buffer.clone())
 4167                                .or_default()
 4168                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4169                        }
 4170                    }
 4171                } else {
 4172                    clear_linked_edit_ranges = true;
 4173                }
 4174            }
 4175
 4176            new_selections.push((selection.map(|_| anchor), 0));
 4177            edits.push((selection.start..selection.end, text.clone()));
 4178        }
 4179
 4180        drop(snapshot);
 4181
 4182        self.transact(window, cx, |this, window, cx| {
 4183            if clear_linked_edit_ranges {
 4184                this.linked_edit_ranges.clear();
 4185            }
 4186            let initial_buffer_versions =
 4187                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4188
 4189            this.buffer.update(cx, |buffer, cx| {
 4190                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4191            });
 4192            for (buffer, edits) in linked_edits {
 4193                buffer.update(cx, |buffer, cx| {
 4194                    let snapshot = buffer.snapshot();
 4195                    let edits = edits
 4196                        .into_iter()
 4197                        .map(|(range, text)| {
 4198                            use text::ToPoint as TP;
 4199                            let end_point = TP::to_point(&range.end, &snapshot);
 4200                            let start_point = TP::to_point(&range.start, &snapshot);
 4201                            (start_point..end_point, text)
 4202                        })
 4203                        .sorted_by_key(|(range, _)| range.start);
 4204                    buffer.edit(edits, None, cx);
 4205                })
 4206            }
 4207            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4208            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4209            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4210            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4211                .zip(new_selection_deltas)
 4212                .map(|(selection, delta)| Selection {
 4213                    id: selection.id,
 4214                    start: selection.start + delta,
 4215                    end: selection.end + delta,
 4216                    reversed: selection.reversed,
 4217                    goal: SelectionGoal::None,
 4218                })
 4219                .collect::<Vec<_>>();
 4220
 4221            let mut i = 0;
 4222            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4223                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4224                let start = map.buffer_snapshot.anchor_before(position);
 4225                let end = map.buffer_snapshot.anchor_after(position);
 4226                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4227                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4228                        Ordering::Less => i += 1,
 4229                        Ordering::Greater => break,
 4230                        Ordering::Equal => {
 4231                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4232                                Ordering::Less => i += 1,
 4233                                Ordering::Equal => break,
 4234                                Ordering::Greater => break,
 4235                            }
 4236                        }
 4237                    }
 4238                }
 4239                this.autoclose_regions.insert(
 4240                    i,
 4241                    AutocloseRegion {
 4242                        selection_id,
 4243                        range: start..end,
 4244                        pair,
 4245                    },
 4246                );
 4247            }
 4248
 4249            let had_active_inline_completion = this.has_active_inline_completion();
 4250            this.change_selections(
 4251                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4252                window,
 4253                cx,
 4254                |s| s.select(new_selections),
 4255            );
 4256
 4257            if !bracket_inserted {
 4258                if let Some(on_type_format_task) =
 4259                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4260                {
 4261                    on_type_format_task.detach_and_log_err(cx);
 4262                }
 4263            }
 4264
 4265            let editor_settings = EditorSettings::get_global(cx);
 4266            if bracket_inserted
 4267                && (editor_settings.auto_signature_help
 4268                    || editor_settings.show_signature_help_after_edits)
 4269            {
 4270                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4271            }
 4272
 4273            let trigger_in_words =
 4274                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4275            if this.hard_wrap.is_some() {
 4276                let latest: Range<Point> = this.selections.newest(cx).range();
 4277                if latest.is_empty()
 4278                    && this
 4279                        .buffer()
 4280                        .read(cx)
 4281                        .snapshot(cx)
 4282                        .line_len(MultiBufferRow(latest.start.row))
 4283                        == latest.start.column
 4284                {
 4285                    this.rewrap_impl(
 4286                        RewrapOptions {
 4287                            override_language_settings: true,
 4288                            preserve_existing_whitespace: true,
 4289                        },
 4290                        cx,
 4291                    )
 4292                }
 4293            }
 4294            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4295            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4296            this.refresh_inline_completion(true, false, window, cx);
 4297            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4298        });
 4299    }
 4300
 4301    fn find_possible_emoji_shortcode_at_position(
 4302        snapshot: &MultiBufferSnapshot,
 4303        position: Point,
 4304    ) -> Option<String> {
 4305        let mut chars = Vec::new();
 4306        let mut found_colon = false;
 4307        for char in snapshot.reversed_chars_at(position).take(100) {
 4308            // Found a possible emoji shortcode in the middle of the buffer
 4309            if found_colon {
 4310                if char.is_whitespace() {
 4311                    chars.reverse();
 4312                    return Some(chars.iter().collect());
 4313                }
 4314                // If the previous character is not a whitespace, we are in the middle of a word
 4315                // and we only want to complete the shortcode if the word is made up of other emojis
 4316                let mut containing_word = String::new();
 4317                for ch in snapshot
 4318                    .reversed_chars_at(position)
 4319                    .skip(chars.len() + 1)
 4320                    .take(100)
 4321                {
 4322                    if ch.is_whitespace() {
 4323                        break;
 4324                    }
 4325                    containing_word.push(ch);
 4326                }
 4327                let containing_word = containing_word.chars().rev().collect::<String>();
 4328                if util::word_consists_of_emojis(containing_word.as_str()) {
 4329                    chars.reverse();
 4330                    return Some(chars.iter().collect());
 4331                }
 4332            }
 4333
 4334            if char.is_whitespace() || !char.is_ascii() {
 4335                return None;
 4336            }
 4337            if char == ':' {
 4338                found_colon = true;
 4339            } else {
 4340                chars.push(char);
 4341            }
 4342        }
 4343        // Found a possible emoji shortcode at the beginning of the buffer
 4344        chars.reverse();
 4345        Some(chars.iter().collect())
 4346    }
 4347
 4348    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4350        self.transact(window, cx, |this, window, cx| {
 4351            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4352                let selections = this.selections.all::<usize>(cx);
 4353                let multi_buffer = this.buffer.read(cx);
 4354                let buffer = multi_buffer.snapshot(cx);
 4355                selections
 4356                    .iter()
 4357                    .map(|selection| {
 4358                        let start_point = selection.start.to_point(&buffer);
 4359                        let mut existing_indent =
 4360                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4361                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4362                        let start = selection.start;
 4363                        let end = selection.end;
 4364                        let selection_is_empty = start == end;
 4365                        let language_scope = buffer.language_scope_at(start);
 4366                        let (
 4367                            comment_delimiter,
 4368                            doc_delimiter,
 4369                            insert_extra_newline,
 4370                            indent_on_newline,
 4371                            indent_on_extra_newline,
 4372                        ) = if let Some(language) = &language_scope {
 4373                            let mut insert_extra_newline =
 4374                                insert_extra_newline_brackets(&buffer, start..end, language)
 4375                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4376
 4377                            // Comment extension on newline is allowed only for cursor selections
 4378                            let comment_delimiter = maybe!({
 4379                                if !selection_is_empty {
 4380                                    return None;
 4381                                }
 4382
 4383                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4384                                    return None;
 4385                                }
 4386
 4387                                let delimiters = language.line_comment_prefixes();
 4388                                let max_len_of_delimiter =
 4389                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4390                                let (snapshot, range) =
 4391                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4392
 4393                                let num_of_whitespaces = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .take_while(|c| c.is_whitespace())
 4396                                    .count();
 4397                                let comment_candidate = snapshot
 4398                                    .chars_for_range(range.clone())
 4399                                    .skip(num_of_whitespaces)
 4400                                    .take(max_len_of_delimiter)
 4401                                    .collect::<String>();
 4402                                let (delimiter, trimmed_len) = delimiters
 4403                                    .iter()
 4404                                    .filter_map(|delimiter| {
 4405                                        let prefix = delimiter.trim_end();
 4406                                        if comment_candidate.starts_with(prefix) {
 4407                                            Some((delimiter, prefix.len()))
 4408                                        } else {
 4409                                            None
 4410                                        }
 4411                                    })
 4412                                    .max_by_key(|(_, len)| *len)?;
 4413
 4414                                if let Some(BlockCommentConfig {
 4415                                    start: block_start, ..
 4416                                }) = language.block_comment()
 4417                                {
 4418                                    let block_start_trimmed = block_start.trim_end();
 4419                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4420                                        let line_content = snapshot
 4421                                            .chars_for_range(range)
 4422                                            .skip(num_of_whitespaces)
 4423                                            .take(block_start_trimmed.len())
 4424                                            .collect::<String>();
 4425
 4426                                        if line_content.starts_with(block_start_trimmed) {
 4427                                            return None;
 4428                                        }
 4429                                    }
 4430                                }
 4431
 4432                                let cursor_is_placed_after_comment_marker =
 4433                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4434                                if cursor_is_placed_after_comment_marker {
 4435                                    Some(delimiter.clone())
 4436                                } else {
 4437                                    None
 4438                                }
 4439                            });
 4440
 4441                            let mut indent_on_newline = IndentSize::spaces(0);
 4442                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4443
 4444                            let doc_delimiter = maybe!({
 4445                                if !selection_is_empty {
 4446                                    return None;
 4447                                }
 4448
 4449                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4450                                    return None;
 4451                                }
 4452
 4453                                let BlockCommentConfig {
 4454                                    start: start_tag,
 4455                                    end: end_tag,
 4456                                    prefix: delimiter,
 4457                                    tab_size: len,
 4458                                } = language.documentation_comment()?;
 4459                                let is_within_block_comment = buffer
 4460                                    .language_scope_at(start_point)
 4461                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4462                                if !is_within_block_comment {
 4463                                    return None;
 4464                                }
 4465
 4466                                let (snapshot, range) =
 4467                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4468
 4469                                let num_of_whitespaces = snapshot
 4470                                    .chars_for_range(range.clone())
 4471                                    .take_while(|c| c.is_whitespace())
 4472                                    .count();
 4473
 4474                                // 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.
 4475                                let column = start_point.column;
 4476                                let cursor_is_after_start_tag = {
 4477                                    let start_tag_len = start_tag.len();
 4478                                    let start_tag_line = snapshot
 4479                                        .chars_for_range(range.clone())
 4480                                        .skip(num_of_whitespaces)
 4481                                        .take(start_tag_len)
 4482                                        .collect::<String>();
 4483                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4484                                        num_of_whitespaces + start_tag_len <= column as usize
 4485                                    } else {
 4486                                        false
 4487                                    }
 4488                                };
 4489
 4490                                let cursor_is_after_delimiter = {
 4491                                    let delimiter_trim = delimiter.trim_end();
 4492                                    let delimiter_line = snapshot
 4493                                        .chars_for_range(range.clone())
 4494                                        .skip(num_of_whitespaces)
 4495                                        .take(delimiter_trim.len())
 4496                                        .collect::<String>();
 4497                                    if delimiter_line.starts_with(delimiter_trim) {
 4498                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4499                                    } else {
 4500                                        false
 4501                                    }
 4502                                };
 4503
 4504                                let cursor_is_before_end_tag_if_exists = {
 4505                                    let mut char_position = 0u32;
 4506                                    let mut end_tag_offset = None;
 4507
 4508                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4509                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4510                                            let chars_before_match =
 4511                                                chunk[..byte_pos].chars().count() as u32;
 4512                                            end_tag_offset =
 4513                                                Some(char_position + chars_before_match);
 4514                                            break 'outer;
 4515                                        }
 4516                                        char_position += chunk.chars().count() as u32;
 4517                                    }
 4518
 4519                                    if let Some(end_tag_offset) = end_tag_offset {
 4520                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4521                                        if cursor_is_after_start_tag {
 4522                                            if cursor_is_before_end_tag {
 4523                                                insert_extra_newline = true;
 4524                                            }
 4525                                            let cursor_is_at_start_of_end_tag =
 4526                                                column == end_tag_offset;
 4527                                            if cursor_is_at_start_of_end_tag {
 4528                                                indent_on_extra_newline.len = *len;
 4529                                            }
 4530                                        }
 4531                                        cursor_is_before_end_tag
 4532                                    } else {
 4533                                        true
 4534                                    }
 4535                                };
 4536
 4537                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4538                                    && cursor_is_before_end_tag_if_exists
 4539                                {
 4540                                    if cursor_is_after_start_tag {
 4541                                        indent_on_newline.len = *len;
 4542                                    }
 4543                                    Some(delimiter.clone())
 4544                                } else {
 4545                                    None
 4546                                }
 4547                            });
 4548
 4549                            (
 4550                                comment_delimiter,
 4551                                doc_delimiter,
 4552                                insert_extra_newline,
 4553                                indent_on_newline,
 4554                                indent_on_extra_newline,
 4555                            )
 4556                        } else {
 4557                            (
 4558                                None,
 4559                                None,
 4560                                false,
 4561                                IndentSize::default(),
 4562                                IndentSize::default(),
 4563                            )
 4564                        };
 4565
 4566                        let prevent_auto_indent = doc_delimiter.is_some();
 4567                        let delimiter = comment_delimiter.or(doc_delimiter);
 4568
 4569                        let capacity_for_delimiter =
 4570                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4571                        let mut new_text = String::with_capacity(
 4572                            1 + capacity_for_delimiter
 4573                                + existing_indent.len as usize
 4574                                + indent_on_newline.len as usize
 4575                                + indent_on_extra_newline.len as usize,
 4576                        );
 4577                        new_text.push('\n');
 4578                        new_text.extend(existing_indent.chars());
 4579                        new_text.extend(indent_on_newline.chars());
 4580
 4581                        if let Some(delimiter) = &delimiter {
 4582                            new_text.push_str(delimiter);
 4583                        }
 4584
 4585                        if insert_extra_newline {
 4586                            new_text.push('\n');
 4587                            new_text.extend(existing_indent.chars());
 4588                            new_text.extend(indent_on_extra_newline.chars());
 4589                        }
 4590
 4591                        let anchor = buffer.anchor_after(end);
 4592                        let new_selection = selection.map(|_| anchor);
 4593                        (
 4594                            ((start..end, new_text), prevent_auto_indent),
 4595                            (insert_extra_newline, new_selection),
 4596                        )
 4597                    })
 4598                    .unzip()
 4599            };
 4600
 4601            let mut auto_indent_edits = Vec::new();
 4602            let mut edits = Vec::new();
 4603            for (edit, prevent_auto_indent) in edits_with_flags {
 4604                if prevent_auto_indent {
 4605                    edits.push(edit);
 4606                } else {
 4607                    auto_indent_edits.push(edit);
 4608                }
 4609            }
 4610            if !edits.is_empty() {
 4611                this.edit(edits, cx);
 4612            }
 4613            if !auto_indent_edits.is_empty() {
 4614                this.edit_with_autoindent(auto_indent_edits, cx);
 4615            }
 4616
 4617            let buffer = this.buffer.read(cx).snapshot(cx);
 4618            let new_selections = selection_info
 4619                .into_iter()
 4620                .map(|(extra_newline_inserted, new_selection)| {
 4621                    let mut cursor = new_selection.end.to_point(&buffer);
 4622                    if extra_newline_inserted {
 4623                        cursor.row -= 1;
 4624                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4625                    }
 4626                    new_selection.map(|_| cursor)
 4627                })
 4628                .collect();
 4629
 4630            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4631            this.refresh_inline_completion(true, false, window, cx);
 4632        });
 4633    }
 4634
 4635    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4637
 4638        let buffer = self.buffer.read(cx);
 4639        let snapshot = buffer.snapshot(cx);
 4640
 4641        let mut edits = Vec::new();
 4642        let mut rows = Vec::new();
 4643
 4644        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4645            let cursor = selection.head();
 4646            let row = cursor.row;
 4647
 4648            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4649
 4650            let newline = "\n".to_string();
 4651            edits.push((start_of_line..start_of_line, newline));
 4652
 4653            rows.push(row + rows_inserted as u32);
 4654        }
 4655
 4656        self.transact(window, cx, |editor, window, cx| {
 4657            editor.edit(edits, cx);
 4658
 4659            editor.change_selections(Default::default(), window, cx, |s| {
 4660                let mut index = 0;
 4661                s.move_cursors_with(|map, _, _| {
 4662                    let row = rows[index];
 4663                    index += 1;
 4664
 4665                    let point = Point::new(row, 0);
 4666                    let boundary = map.next_line_boundary(point).1;
 4667                    let clipped = map.clip_point(boundary, Bias::Left);
 4668
 4669                    (clipped, SelectionGoal::None)
 4670                });
 4671            });
 4672
 4673            let mut indent_edits = Vec::new();
 4674            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4675            for row in rows {
 4676                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4677                for (row, indent) in indents {
 4678                    if indent.len == 0 {
 4679                        continue;
 4680                    }
 4681
 4682                    let text = match indent.kind {
 4683                        IndentKind::Space => " ".repeat(indent.len as usize),
 4684                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4685                    };
 4686                    let point = Point::new(row.0, 0);
 4687                    indent_edits.push((point..point, text));
 4688                }
 4689            }
 4690            editor.edit(indent_edits, cx);
 4691        });
 4692    }
 4693
 4694    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4696
 4697        let buffer = self.buffer.read(cx);
 4698        let snapshot = buffer.snapshot(cx);
 4699
 4700        let mut edits = Vec::new();
 4701        let mut rows = Vec::new();
 4702        let mut rows_inserted = 0;
 4703
 4704        for selection in self.selections.all_adjusted(cx) {
 4705            let cursor = selection.head();
 4706            let row = cursor.row;
 4707
 4708            let point = Point::new(row + 1, 0);
 4709            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4710
 4711            let newline = "\n".to_string();
 4712            edits.push((start_of_line..start_of_line, newline));
 4713
 4714            rows_inserted += 1;
 4715            rows.push(row + rows_inserted);
 4716        }
 4717
 4718        self.transact(window, cx, |editor, window, cx| {
 4719            editor.edit(edits, cx);
 4720
 4721            editor.change_selections(Default::default(), window, cx, |s| {
 4722                let mut index = 0;
 4723                s.move_cursors_with(|map, _, _| {
 4724                    let row = rows[index];
 4725                    index += 1;
 4726
 4727                    let point = Point::new(row, 0);
 4728                    let boundary = map.next_line_boundary(point).1;
 4729                    let clipped = map.clip_point(boundary, Bias::Left);
 4730
 4731                    (clipped, SelectionGoal::None)
 4732                });
 4733            });
 4734
 4735            let mut indent_edits = Vec::new();
 4736            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4737            for row in rows {
 4738                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4739                for (row, indent) in indents {
 4740                    if indent.len == 0 {
 4741                        continue;
 4742                    }
 4743
 4744                    let text = match indent.kind {
 4745                        IndentKind::Space => " ".repeat(indent.len as usize),
 4746                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4747                    };
 4748                    let point = Point::new(row.0, 0);
 4749                    indent_edits.push((point..point, text));
 4750                }
 4751            }
 4752            editor.edit(indent_edits, cx);
 4753        });
 4754    }
 4755
 4756    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4757        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4758            original_indent_columns: Vec::new(),
 4759        });
 4760        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4761    }
 4762
 4763    fn insert_with_autoindent_mode(
 4764        &mut self,
 4765        text: &str,
 4766        autoindent_mode: Option<AutoindentMode>,
 4767        window: &mut Window,
 4768        cx: &mut Context<Self>,
 4769    ) {
 4770        if self.read_only(cx) {
 4771            return;
 4772        }
 4773
 4774        let text: Arc<str> = text.into();
 4775        self.transact(window, cx, |this, window, cx| {
 4776            let old_selections = this.selections.all_adjusted(cx);
 4777            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4778                let anchors = {
 4779                    let snapshot = buffer.read(cx);
 4780                    old_selections
 4781                        .iter()
 4782                        .map(|s| {
 4783                            let anchor = snapshot.anchor_after(s.head());
 4784                            s.map(|_| anchor)
 4785                        })
 4786                        .collect::<Vec<_>>()
 4787                };
 4788                buffer.edit(
 4789                    old_selections
 4790                        .iter()
 4791                        .map(|s| (s.start..s.end, text.clone())),
 4792                    autoindent_mode,
 4793                    cx,
 4794                );
 4795                anchors
 4796            });
 4797
 4798            this.change_selections(Default::default(), window, cx, |s| {
 4799                s.select_anchors(selection_anchors);
 4800            });
 4801
 4802            cx.notify();
 4803        });
 4804    }
 4805
 4806    fn trigger_completion_on_input(
 4807        &mut self,
 4808        text: &str,
 4809        trigger_in_words: bool,
 4810        window: &mut Window,
 4811        cx: &mut Context<Self>,
 4812    ) {
 4813        let completions_source = self
 4814            .context_menu
 4815            .borrow()
 4816            .as_ref()
 4817            .and_then(|menu| match menu {
 4818                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4819                CodeContextMenu::CodeActions(_) => None,
 4820            });
 4821
 4822        match completions_source {
 4823            Some(CompletionsMenuSource::Words) => {
 4824                self.show_word_completions(&ShowWordCompletions, window, cx)
 4825            }
 4826            Some(CompletionsMenuSource::Normal)
 4827            | Some(CompletionsMenuSource::SnippetChoices)
 4828            | None
 4829                if self.is_completion_trigger(
 4830                    text,
 4831                    trigger_in_words,
 4832                    completions_source.is_some(),
 4833                    cx,
 4834                ) =>
 4835            {
 4836                self.show_completions(
 4837                    &ShowCompletions {
 4838                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4839                    },
 4840                    window,
 4841                    cx,
 4842                )
 4843            }
 4844            _ => {
 4845                self.hide_context_menu(window, cx);
 4846            }
 4847        }
 4848    }
 4849
 4850    fn is_completion_trigger(
 4851        &self,
 4852        text: &str,
 4853        trigger_in_words: bool,
 4854        menu_is_open: bool,
 4855        cx: &mut Context<Self>,
 4856    ) -> bool {
 4857        let position = self.selections.newest_anchor().head();
 4858        let multibuffer = self.buffer.read(cx);
 4859        let Some(buffer) = position
 4860            .buffer_id
 4861            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4862        else {
 4863            return false;
 4864        };
 4865
 4866        if let Some(completion_provider) = &self.completion_provider {
 4867            completion_provider.is_completion_trigger(
 4868                &buffer,
 4869                position.text_anchor,
 4870                text,
 4871                trigger_in_words,
 4872                menu_is_open,
 4873                cx,
 4874            )
 4875        } else {
 4876            false
 4877        }
 4878    }
 4879
 4880    /// If any empty selections is touching the start of its innermost containing autoclose
 4881    /// region, expand it to select the brackets.
 4882    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4883        let selections = self.selections.all::<usize>(cx);
 4884        let buffer = self.buffer.read(cx).read(cx);
 4885        let new_selections = self
 4886            .selections_with_autoclose_regions(selections, &buffer)
 4887            .map(|(mut selection, region)| {
 4888                if !selection.is_empty() {
 4889                    return selection;
 4890                }
 4891
 4892                if let Some(region) = region {
 4893                    let mut range = region.range.to_offset(&buffer);
 4894                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4895                        range.start -= region.pair.start.len();
 4896                        if buffer.contains_str_at(range.start, &region.pair.start)
 4897                            && buffer.contains_str_at(range.end, &region.pair.end)
 4898                        {
 4899                            range.end += region.pair.end.len();
 4900                            selection.start = range.start;
 4901                            selection.end = range.end;
 4902
 4903                            return selection;
 4904                        }
 4905                    }
 4906                }
 4907
 4908                let always_treat_brackets_as_autoclosed = buffer
 4909                    .language_settings_at(selection.start, cx)
 4910                    .always_treat_brackets_as_autoclosed;
 4911
 4912                if !always_treat_brackets_as_autoclosed {
 4913                    return selection;
 4914                }
 4915
 4916                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4917                    for (pair, enabled) in scope.brackets() {
 4918                        if !enabled || !pair.close {
 4919                            continue;
 4920                        }
 4921
 4922                        if buffer.contains_str_at(selection.start, &pair.end) {
 4923                            let pair_start_len = pair.start.len();
 4924                            if buffer.contains_str_at(
 4925                                selection.start.saturating_sub(pair_start_len),
 4926                                &pair.start,
 4927                            ) {
 4928                                selection.start -= pair_start_len;
 4929                                selection.end += pair.end.len();
 4930
 4931                                return selection;
 4932                            }
 4933                        }
 4934                    }
 4935                }
 4936
 4937                selection
 4938            })
 4939            .collect();
 4940
 4941        drop(buffer);
 4942        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4943            selections.select(new_selections)
 4944        });
 4945    }
 4946
 4947    /// Iterate the given selections, and for each one, find the smallest surrounding
 4948    /// autoclose region. This uses the ordering of the selections and the autoclose
 4949    /// regions to avoid repeated comparisons.
 4950    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4951        &'a self,
 4952        selections: impl IntoIterator<Item = Selection<D>>,
 4953        buffer: &'a MultiBufferSnapshot,
 4954    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4955        let mut i = 0;
 4956        let mut regions = self.autoclose_regions.as_slice();
 4957        selections.into_iter().map(move |selection| {
 4958            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4959
 4960            let mut enclosing = None;
 4961            while let Some(pair_state) = regions.get(i) {
 4962                if pair_state.range.end.to_offset(buffer) < range.start {
 4963                    regions = &regions[i + 1..];
 4964                    i = 0;
 4965                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4966                    break;
 4967                } else {
 4968                    if pair_state.selection_id == selection.id {
 4969                        enclosing = Some(pair_state);
 4970                    }
 4971                    i += 1;
 4972                }
 4973            }
 4974
 4975            (selection, enclosing)
 4976        })
 4977    }
 4978
 4979    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4980    fn invalidate_autoclose_regions(
 4981        &mut self,
 4982        mut selections: &[Selection<Anchor>],
 4983        buffer: &MultiBufferSnapshot,
 4984    ) {
 4985        self.autoclose_regions.retain(|state| {
 4986            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4987                return false;
 4988            }
 4989
 4990            let mut i = 0;
 4991            while let Some(selection) = selections.get(i) {
 4992                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4993                    selections = &selections[1..];
 4994                    continue;
 4995                }
 4996                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4997                    break;
 4998                }
 4999                if selection.id == state.selection_id {
 5000                    return true;
 5001                } else {
 5002                    i += 1;
 5003                }
 5004            }
 5005            false
 5006        });
 5007    }
 5008
 5009    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5010        let offset = position.to_offset(buffer);
 5011        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5012        if offset > word_range.start && kind == Some(CharKind::Word) {
 5013            Some(
 5014                buffer
 5015                    .text_for_range(word_range.start..offset)
 5016                    .collect::<String>(),
 5017            )
 5018        } else {
 5019            None
 5020        }
 5021    }
 5022
 5023    pub fn toggle_inline_values(
 5024        &mut self,
 5025        _: &ToggleInlineValues,
 5026        _: &mut Window,
 5027        cx: &mut Context<Self>,
 5028    ) {
 5029        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5030
 5031        self.refresh_inline_values(cx);
 5032    }
 5033
 5034    pub fn toggle_inlay_hints(
 5035        &mut self,
 5036        _: &ToggleInlayHints,
 5037        _: &mut Window,
 5038        cx: &mut Context<Self>,
 5039    ) {
 5040        self.refresh_inlay_hints(
 5041            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5042            cx,
 5043        );
 5044    }
 5045
 5046    pub fn inlay_hints_enabled(&self) -> bool {
 5047        self.inlay_hint_cache.enabled
 5048    }
 5049
 5050    pub fn inline_values_enabled(&self) -> bool {
 5051        self.inline_value_cache.enabled
 5052    }
 5053
 5054    #[cfg(any(test, feature = "test-support"))]
 5055    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5056        self.display_map
 5057            .read(cx)
 5058            .current_inlays()
 5059            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5060            .cloned()
 5061            .collect()
 5062    }
 5063
 5064    #[cfg(any(test, feature = "test-support"))]
 5065    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5066        self.display_map
 5067            .read(cx)
 5068            .current_inlays()
 5069            .cloned()
 5070            .collect()
 5071    }
 5072
 5073    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5074        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5075            return;
 5076        }
 5077
 5078        let reason_description = reason.description();
 5079        let ignore_debounce = matches!(
 5080            reason,
 5081            InlayHintRefreshReason::SettingsChange(_)
 5082                | InlayHintRefreshReason::Toggle(_)
 5083                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5084                | InlayHintRefreshReason::ModifiersChanged(_)
 5085        );
 5086        let (invalidate_cache, required_languages) = match reason {
 5087            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5088                match self.inlay_hint_cache.modifiers_override(enabled) {
 5089                    Some(enabled) => {
 5090                        if enabled {
 5091                            (InvalidationStrategy::RefreshRequested, None)
 5092                        } else {
 5093                            self.splice_inlays(
 5094                                &self
 5095                                    .visible_inlay_hints(cx)
 5096                                    .iter()
 5097                                    .map(|inlay| inlay.id)
 5098                                    .collect::<Vec<InlayId>>(),
 5099                                Vec::new(),
 5100                                cx,
 5101                            );
 5102                            return;
 5103                        }
 5104                    }
 5105                    None => return,
 5106                }
 5107            }
 5108            InlayHintRefreshReason::Toggle(enabled) => {
 5109                if self.inlay_hint_cache.toggle(enabled) {
 5110                    if enabled {
 5111                        (InvalidationStrategy::RefreshRequested, None)
 5112                    } else {
 5113                        self.splice_inlays(
 5114                            &self
 5115                                .visible_inlay_hints(cx)
 5116                                .iter()
 5117                                .map(|inlay| inlay.id)
 5118                                .collect::<Vec<InlayId>>(),
 5119                            Vec::new(),
 5120                            cx,
 5121                        );
 5122                        return;
 5123                    }
 5124                } else {
 5125                    return;
 5126                }
 5127            }
 5128            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5129                match self.inlay_hint_cache.update_settings(
 5130                    &self.buffer,
 5131                    new_settings,
 5132                    self.visible_inlay_hints(cx),
 5133                    cx,
 5134                ) {
 5135                    ControlFlow::Break(Some(InlaySplice {
 5136                        to_remove,
 5137                        to_insert,
 5138                    })) => {
 5139                        self.splice_inlays(&to_remove, to_insert, cx);
 5140                        return;
 5141                    }
 5142                    ControlFlow::Break(None) => return,
 5143                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5144                }
 5145            }
 5146            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5147                if let Some(InlaySplice {
 5148                    to_remove,
 5149                    to_insert,
 5150                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5151                {
 5152                    self.splice_inlays(&to_remove, to_insert, cx);
 5153                }
 5154                self.display_map.update(cx, |display_map, _| {
 5155                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5156                });
 5157                return;
 5158            }
 5159            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5160            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5161                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5162            }
 5163            InlayHintRefreshReason::RefreshRequested => {
 5164                (InvalidationStrategy::RefreshRequested, None)
 5165            }
 5166        };
 5167
 5168        if let Some(InlaySplice {
 5169            to_remove,
 5170            to_insert,
 5171        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5172            reason_description,
 5173            self.visible_excerpts(required_languages.as_ref(), cx),
 5174            invalidate_cache,
 5175            ignore_debounce,
 5176            cx,
 5177        ) {
 5178            self.splice_inlays(&to_remove, to_insert, cx);
 5179        }
 5180    }
 5181
 5182    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5183        self.display_map
 5184            .read(cx)
 5185            .current_inlays()
 5186            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    pub fn visible_excerpts(
 5192        &self,
 5193        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5194        cx: &mut Context<Editor>,
 5195    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5196        let Some(project) = self.project.as_ref() else {
 5197            return HashMap::default();
 5198        };
 5199        let project = project.read(cx);
 5200        let multi_buffer = self.buffer().read(cx);
 5201        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5202        let multi_buffer_visible_start = self
 5203            .scroll_manager
 5204            .anchor()
 5205            .anchor
 5206            .to_point(&multi_buffer_snapshot);
 5207        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5208            multi_buffer_visible_start
 5209                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5210            Bias::Left,
 5211        );
 5212        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5213        multi_buffer_snapshot
 5214            .range_to_buffer_ranges(multi_buffer_visible_range)
 5215            .into_iter()
 5216            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5217            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5218                let buffer_file = project::File::from_dyn(buffer.file())?;
 5219                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5220                let worktree_entry = buffer_worktree
 5221                    .read(cx)
 5222                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5223                if worktree_entry.is_ignored {
 5224                    return None;
 5225                }
 5226
 5227                let language = buffer.language()?;
 5228                if let Some(restrict_to_languages) = restrict_to_languages {
 5229                    if !restrict_to_languages.contains(language) {
 5230                        return None;
 5231                    }
 5232                }
 5233                Some((
 5234                    excerpt_id,
 5235                    (
 5236                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5237                        buffer.version().clone(),
 5238                        excerpt_visible_range,
 5239                    ),
 5240                ))
 5241            })
 5242            .collect()
 5243    }
 5244
 5245    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5246        TextLayoutDetails {
 5247            text_system: window.text_system().clone(),
 5248            editor_style: self.style.clone().unwrap(),
 5249            rem_size: window.rem_size(),
 5250            scroll_anchor: self.scroll_manager.anchor(),
 5251            visible_rows: self.visible_line_count(),
 5252            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5253        }
 5254    }
 5255
 5256    pub fn splice_inlays(
 5257        &self,
 5258        to_remove: &[InlayId],
 5259        to_insert: Vec<Inlay>,
 5260        cx: &mut Context<Self>,
 5261    ) {
 5262        self.display_map.update(cx, |display_map, cx| {
 5263            display_map.splice_inlays(to_remove, to_insert, cx)
 5264        });
 5265        cx.notify();
 5266    }
 5267
 5268    fn trigger_on_type_formatting(
 5269        &self,
 5270        input: String,
 5271        window: &mut Window,
 5272        cx: &mut Context<Self>,
 5273    ) -> Option<Task<Result<()>>> {
 5274        if input.len() != 1 {
 5275            return None;
 5276        }
 5277
 5278        let project = self.project.as_ref()?;
 5279        let position = self.selections.newest_anchor().head();
 5280        let (buffer, buffer_position) = self
 5281            .buffer
 5282            .read(cx)
 5283            .text_anchor_for_position(position, cx)?;
 5284
 5285        let settings = language_settings::language_settings(
 5286            buffer
 5287                .read(cx)
 5288                .language_at(buffer_position)
 5289                .map(|l| l.name()),
 5290            buffer.read(cx).file(),
 5291            cx,
 5292        );
 5293        if !settings.use_on_type_format {
 5294            return None;
 5295        }
 5296
 5297        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5298        // hence we do LSP request & edit on host side only — add formats to host's history.
 5299        let push_to_lsp_host_history = true;
 5300        // If this is not the host, append its history with new edits.
 5301        let push_to_client_history = project.read(cx).is_via_collab();
 5302
 5303        let on_type_formatting = project.update(cx, |project, cx| {
 5304            project.on_type_format(
 5305                buffer.clone(),
 5306                buffer_position,
 5307                input,
 5308                push_to_lsp_host_history,
 5309                cx,
 5310            )
 5311        });
 5312        Some(cx.spawn_in(window, async move |editor, cx| {
 5313            if let Some(transaction) = on_type_formatting.await? {
 5314                if push_to_client_history {
 5315                    buffer
 5316                        .update(cx, |buffer, _| {
 5317                            buffer.push_transaction(transaction, Instant::now());
 5318                            buffer.finalize_last_transaction();
 5319                        })
 5320                        .ok();
 5321                }
 5322                editor.update(cx, |editor, cx| {
 5323                    editor.refresh_document_highlights(cx);
 5324                })?;
 5325            }
 5326            Ok(())
 5327        }))
 5328    }
 5329
 5330    pub fn show_word_completions(
 5331        &mut self,
 5332        _: &ShowWordCompletions,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5337    }
 5338
 5339    pub fn show_completions(
 5340        &mut self,
 5341        options: &ShowCompletions,
 5342        window: &mut Window,
 5343        cx: &mut Context<Self>,
 5344    ) {
 5345        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5346    }
 5347
 5348    fn open_or_update_completions_menu(
 5349        &mut self,
 5350        requested_source: Option<CompletionsMenuSource>,
 5351        trigger: Option<&str>,
 5352        window: &mut Window,
 5353        cx: &mut Context<Self>,
 5354    ) {
 5355        if self.pending_rename.is_some() {
 5356            return;
 5357        }
 5358
 5359        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5360
 5361        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5362        // inserted and selected. To handle that case, the start of the selection is used so that
 5363        // the menu starts with all choices.
 5364        let position = self
 5365            .selections
 5366            .newest_anchor()
 5367            .start
 5368            .bias_right(&multibuffer_snapshot);
 5369        if position.diff_base_anchor.is_some() {
 5370            return;
 5371        }
 5372        let (buffer, buffer_position) =
 5373            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5374                output
 5375            } else {
 5376                return;
 5377            };
 5378        let buffer_snapshot = buffer.read(cx).snapshot();
 5379
 5380        let query: Option<Arc<String>> =
 5381            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5382
 5383        drop(multibuffer_snapshot);
 5384
 5385        let provider = match requested_source {
 5386            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5387            Some(CompletionsMenuSource::Words) => None,
 5388            Some(CompletionsMenuSource::SnippetChoices) => {
 5389                log::error!("bug: SnippetChoices requested_source is not handled");
 5390                None
 5391            }
 5392        };
 5393
 5394        let sort_completions = provider
 5395            .as_ref()
 5396            .map_or(false, |provider| provider.sort_completions());
 5397
 5398        let filter_completions = provider
 5399            .as_ref()
 5400            .map_or(true, |provider| provider.filter_completions());
 5401
 5402        let trigger_kind = match trigger {
 5403            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5404                CompletionTriggerKind::TRIGGER_CHARACTER
 5405            }
 5406            _ => CompletionTriggerKind::INVOKED,
 5407        };
 5408        let completion_context = CompletionContext {
 5409            trigger_character: trigger.and_then(|trigger| {
 5410                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5411                    Some(String::from(trigger))
 5412                } else {
 5413                    None
 5414                }
 5415            }),
 5416            trigger_kind,
 5417        };
 5418
 5419        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5420        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5421        // involve trigger chars, so this is skipped in that case.
 5422        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5423        {
 5424            let menu_is_open = matches!(
 5425                self.context_menu.borrow().as_ref(),
 5426                Some(CodeContextMenu::Completions(_))
 5427            );
 5428            if menu_is_open {
 5429                self.hide_context_menu(window, cx);
 5430            }
 5431        }
 5432
 5433        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5434            if filter_completions {
 5435                menu.filter(query.clone(), provider.clone(), window, cx);
 5436            }
 5437            // When `is_incomplete` is false, no need to re-query completions when the current query
 5438            // is a suffix of the initial query.
 5439            if !menu.is_incomplete {
 5440                // If the new query is a suffix of the old query (typing more characters) and
 5441                // the previous result was complete, the existing completions can be filtered.
 5442                //
 5443                // Note that this is always true for snippet completions.
 5444                let query_matches = match (&menu.initial_query, &query) {
 5445                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5446                    (None, _) => true,
 5447                    _ => false,
 5448                };
 5449                if query_matches {
 5450                    let position_matches = if menu.initial_position == position {
 5451                        true
 5452                    } else {
 5453                        let snapshot = self.buffer.read(cx).read(cx);
 5454                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5455                    };
 5456                    if position_matches {
 5457                        return;
 5458                    }
 5459                }
 5460            }
 5461        };
 5462
 5463        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5464            buffer_snapshot.surrounding_word(buffer_position, false)
 5465        {
 5466            let word_to_exclude = buffer_snapshot
 5467                .text_for_range(word_range.clone())
 5468                .collect::<String>();
 5469            (
 5470                buffer_snapshot.anchor_before(word_range.start)
 5471                    ..buffer_snapshot.anchor_after(buffer_position),
 5472                Some(word_to_exclude),
 5473            )
 5474        } else {
 5475            (buffer_position..buffer_position, None)
 5476        };
 5477
 5478        let language = buffer_snapshot
 5479            .language_at(buffer_position)
 5480            .map(|language| language.name());
 5481
 5482        let completion_settings =
 5483            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5484
 5485        let show_completion_documentation = buffer_snapshot
 5486            .settings_at(buffer_position, cx)
 5487            .show_completion_documentation;
 5488
 5489        // The document can be large, so stay in reasonable bounds when searching for words,
 5490        // otherwise completion pop-up might be slow to appear.
 5491        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5492        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5493        let min_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5495            Bias::Left,
 5496        );
 5497        let max_word_search = buffer_snapshot.clip_point(
 5498            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5499            Bias::Right,
 5500        );
 5501        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5502            ..buffer_snapshot.point_to_offset(max_word_search);
 5503
 5504        let skip_digits = query
 5505            .as_ref()
 5506            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5507
 5508        let (mut words, provider_responses) = match &provider {
 5509            Some(provider) => {
 5510                let provider_responses = provider.completions(
 5511                    position.excerpt_id,
 5512                    &buffer,
 5513                    buffer_position,
 5514                    completion_context,
 5515                    window,
 5516                    cx,
 5517                );
 5518
 5519                let words = match completion_settings.words {
 5520                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5521                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5522                        .background_spawn(async move {
 5523                            buffer_snapshot.words_in_range(WordsQuery {
 5524                                fuzzy_contents: None,
 5525                                range: word_search_range,
 5526                                skip_digits,
 5527                            })
 5528                        }),
 5529                };
 5530
 5531                (words, provider_responses)
 5532            }
 5533            None => (
 5534                cx.background_spawn(async move {
 5535                    buffer_snapshot.words_in_range(WordsQuery {
 5536                        fuzzy_contents: None,
 5537                        range: word_search_range,
 5538                        skip_digits,
 5539                    })
 5540                }),
 5541                Task::ready(Ok(Vec::new())),
 5542            ),
 5543        };
 5544
 5545        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5546
 5547        let id = post_inc(&mut self.next_completion_id);
 5548        let task = cx.spawn_in(window, async move |editor, cx| {
 5549            let Ok(()) = editor.update(cx, |this, _| {
 5550                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5551            }) else {
 5552                return;
 5553            };
 5554
 5555            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5556            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5557            let mut completions = Vec::new();
 5558            let mut is_incomplete = false;
 5559            if let Some(provider_responses) = provider_responses.await.log_err() {
 5560                if !provider_responses.is_empty() {
 5561                    for response in provider_responses {
 5562                        completions.extend(response.completions);
 5563                        is_incomplete = is_incomplete || response.is_incomplete;
 5564                    }
 5565                    if completion_settings.words == WordsCompletionMode::Fallback {
 5566                        words = Task::ready(BTreeMap::default());
 5567                    }
 5568                }
 5569            }
 5570
 5571            let mut words = words.await;
 5572            if let Some(word_to_exclude) = &word_to_exclude {
 5573                words.remove(word_to_exclude);
 5574            }
 5575            for lsp_completion in &completions {
 5576                words.remove(&lsp_completion.new_text);
 5577            }
 5578            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5579                replace_range: word_replace_range.clone(),
 5580                new_text: word.clone(),
 5581                label: CodeLabel::plain(word, None),
 5582                icon_path: None,
 5583                documentation: None,
 5584                source: CompletionSource::BufferWord {
 5585                    word_range,
 5586                    resolved: false,
 5587                },
 5588                insert_text_mode: Some(InsertTextMode::AS_IS),
 5589                confirm: None,
 5590            }));
 5591
 5592            let menu = if completions.is_empty() {
 5593                None
 5594            } else {
 5595                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5596                    let languages = editor
 5597                        .workspace
 5598                        .as_ref()
 5599                        .and_then(|(workspace, _)| workspace.upgrade())
 5600                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5601                    let menu = CompletionsMenu::new(
 5602                        id,
 5603                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5604                        sort_completions,
 5605                        show_completion_documentation,
 5606                        position,
 5607                        query.clone(),
 5608                        is_incomplete,
 5609                        buffer.clone(),
 5610                        completions.into(),
 5611                        snippet_sort_order,
 5612                        languages,
 5613                        language,
 5614                        cx,
 5615                    );
 5616
 5617                    let query = if filter_completions { query } else { None };
 5618                    let matches_task = if let Some(query) = query {
 5619                        menu.do_async_filtering(query, cx)
 5620                    } else {
 5621                        Task::ready(menu.unfiltered_matches())
 5622                    };
 5623                    (menu, matches_task)
 5624                }) else {
 5625                    return;
 5626                };
 5627
 5628                let matches = matches_task.await;
 5629
 5630                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5631                    // Newer menu already set, so exit.
 5632                    match editor.context_menu.borrow().as_ref() {
 5633                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5634                            if prev_menu.id > id {
 5635                                return;
 5636                            }
 5637                        }
 5638                        _ => {}
 5639                    };
 5640
 5641                    // Only valid to take prev_menu because it the new menu is immediately set
 5642                    // below, or the menu is hidden.
 5643                    match editor.context_menu.borrow_mut().take() {
 5644                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5645                            let position_matches =
 5646                                if prev_menu.initial_position == menu.initial_position {
 5647                                    true
 5648                                } else {
 5649                                    let snapshot = editor.buffer.read(cx).read(cx);
 5650                                    prev_menu.initial_position.to_offset(&snapshot)
 5651                                        == menu.initial_position.to_offset(&snapshot)
 5652                                };
 5653                            if position_matches {
 5654                                // Preserve markdown cache before `set_filter_results` because it will
 5655                                // try to populate the documentation cache.
 5656                                menu.preserve_markdown_cache(prev_menu);
 5657                            }
 5658                        }
 5659                        _ => {}
 5660                    };
 5661
 5662                    menu.set_filter_results(matches, provider, window, cx);
 5663                }) else {
 5664                    return;
 5665                };
 5666
 5667                menu.visible().then_some(menu)
 5668            };
 5669
 5670            editor
 5671                .update_in(cx, |editor, window, cx| {
 5672                    if editor.focus_handle.is_focused(window) {
 5673                        if let Some(menu) = menu {
 5674                            *editor.context_menu.borrow_mut() =
 5675                                Some(CodeContextMenu::Completions(menu));
 5676
 5677                            crate::hover_popover::hide_hover(editor, cx);
 5678                            if editor.show_edit_predictions_in_menu() {
 5679                                editor.update_visible_inline_completion(window, cx);
 5680                            } else {
 5681                                editor.discard_inline_completion(false, cx);
 5682                            }
 5683
 5684                            cx.notify();
 5685                            return;
 5686                        }
 5687                    }
 5688
 5689                    if editor.completion_tasks.len() <= 1 {
 5690                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5691                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5692                        // If it was already hidden and we don't show inline completions in the menu, we should
 5693                        // also show the inline-completion when available.
 5694                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5695                            editor.update_visible_inline_completion(window, cx);
 5696                        }
 5697                    }
 5698                })
 5699                .ok();
 5700        });
 5701
 5702        self.completion_tasks.push((id, task));
 5703    }
 5704
 5705    #[cfg(feature = "test-support")]
 5706    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5707        let menu = self.context_menu.borrow();
 5708        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5709            let completions = menu.completions.borrow();
 5710            Some(completions.to_vec())
 5711        } else {
 5712            None
 5713        }
 5714    }
 5715
 5716    pub fn with_completions_menu_matching_id<R>(
 5717        &self,
 5718        id: CompletionId,
 5719        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5720    ) -> R {
 5721        let mut context_menu = self.context_menu.borrow_mut();
 5722        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5723            return f(None);
 5724        };
 5725        if completions_menu.id != id {
 5726            return f(None);
 5727        }
 5728        f(Some(completions_menu))
 5729    }
 5730
 5731    pub fn confirm_completion(
 5732        &mut self,
 5733        action: &ConfirmCompletion,
 5734        window: &mut Window,
 5735        cx: &mut Context<Self>,
 5736    ) -> Option<Task<Result<()>>> {
 5737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5738        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5739    }
 5740
 5741    pub fn confirm_completion_insert(
 5742        &mut self,
 5743        _: &ConfirmCompletionInsert,
 5744        window: &mut Window,
 5745        cx: &mut Context<Self>,
 5746    ) -> Option<Task<Result<()>>> {
 5747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5748        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5749    }
 5750
 5751    pub fn confirm_completion_replace(
 5752        &mut self,
 5753        _: &ConfirmCompletionReplace,
 5754        window: &mut Window,
 5755        cx: &mut Context<Self>,
 5756    ) -> Option<Task<Result<()>>> {
 5757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5758        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5759    }
 5760
 5761    pub fn compose_completion(
 5762        &mut self,
 5763        action: &ComposeCompletion,
 5764        window: &mut Window,
 5765        cx: &mut Context<Self>,
 5766    ) -> Option<Task<Result<()>>> {
 5767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5768        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5769    }
 5770
 5771    fn do_completion(
 5772        &mut self,
 5773        item_ix: Option<usize>,
 5774        intent: CompletionIntent,
 5775        window: &mut Window,
 5776        cx: &mut Context<Editor>,
 5777    ) -> Option<Task<Result<()>>> {
 5778        use language::ToOffset as _;
 5779
 5780        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5781        else {
 5782            return None;
 5783        };
 5784
 5785        let candidate_id = {
 5786            let entries = completions_menu.entries.borrow();
 5787            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5788            if self.show_edit_predictions_in_menu() {
 5789                self.discard_inline_completion(true, cx);
 5790            }
 5791            mat.candidate_id
 5792        };
 5793
 5794        let completion = completions_menu
 5795            .completions
 5796            .borrow()
 5797            .get(candidate_id)?
 5798            .clone();
 5799        cx.stop_propagation();
 5800
 5801        let buffer_handle = completions_menu.buffer.clone();
 5802
 5803        let CompletionEdit {
 5804            new_text,
 5805            snippet,
 5806            replace_range,
 5807        } = process_completion_for_edit(
 5808            &completion,
 5809            intent,
 5810            &buffer_handle,
 5811            &completions_menu.initial_position.text_anchor,
 5812            cx,
 5813        );
 5814
 5815        let buffer = buffer_handle.read(cx);
 5816        let snapshot = self.buffer.read(cx).snapshot(cx);
 5817        let newest_anchor = self.selections.newest_anchor();
 5818        let replace_range_multibuffer = {
 5819            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5820            let multibuffer_anchor = snapshot
 5821                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5822                .unwrap()
 5823                ..snapshot
 5824                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5825                    .unwrap();
 5826            multibuffer_anchor.start.to_offset(&snapshot)
 5827                ..multibuffer_anchor.end.to_offset(&snapshot)
 5828        };
 5829        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5830            return None;
 5831        }
 5832
 5833        let old_text = buffer
 5834            .text_for_range(replace_range.clone())
 5835            .collect::<String>();
 5836        let lookbehind = newest_anchor
 5837            .start
 5838            .text_anchor
 5839            .to_offset(buffer)
 5840            .saturating_sub(replace_range.start);
 5841        let lookahead = replace_range
 5842            .end
 5843            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5844        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5845        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5846
 5847        let selections = self.selections.all::<usize>(cx);
 5848        let mut ranges = Vec::new();
 5849        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5850
 5851        for selection in &selections {
 5852            let range = if selection.id == newest_anchor.id {
 5853                replace_range_multibuffer.clone()
 5854            } else {
 5855                let mut range = selection.range();
 5856
 5857                // if prefix is present, don't duplicate it
 5858                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5859                    range.start = range.start.saturating_sub(lookbehind);
 5860
 5861                    // if suffix is also present, mimic the newest cursor and replace it
 5862                    if selection.id != newest_anchor.id
 5863                        && snapshot.contains_str_at(range.end, suffix)
 5864                    {
 5865                        range.end += lookahead;
 5866                    }
 5867                }
 5868                range
 5869            };
 5870
 5871            ranges.push(range.clone());
 5872
 5873            if !self.linked_edit_ranges.is_empty() {
 5874                let start_anchor = snapshot.anchor_before(range.start);
 5875                let end_anchor = snapshot.anchor_after(range.end);
 5876                if let Some(ranges) = self
 5877                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5878                {
 5879                    for (buffer, edits) in ranges {
 5880                        linked_edits
 5881                            .entry(buffer.clone())
 5882                            .or_default()
 5883                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5884                    }
 5885                }
 5886            }
 5887        }
 5888
 5889        let common_prefix_len = old_text
 5890            .chars()
 5891            .zip(new_text.chars())
 5892            .take_while(|(a, b)| a == b)
 5893            .map(|(a, _)| a.len_utf8())
 5894            .sum::<usize>();
 5895
 5896        cx.emit(EditorEvent::InputHandled {
 5897            utf16_range_to_replace: None,
 5898            text: new_text[common_prefix_len..].into(),
 5899        });
 5900
 5901        self.transact(window, cx, |editor, window, cx| {
 5902            if let Some(mut snippet) = snippet {
 5903                snippet.text = new_text.to_string();
 5904                editor
 5905                    .insert_snippet(&ranges, snippet, window, cx)
 5906                    .log_err();
 5907            } else {
 5908                editor.buffer.update(cx, |multi_buffer, cx| {
 5909                    let auto_indent = match completion.insert_text_mode {
 5910                        Some(InsertTextMode::AS_IS) => None,
 5911                        _ => editor.autoindent_mode.clone(),
 5912                    };
 5913                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5914                    multi_buffer.edit(edits, auto_indent, cx);
 5915                });
 5916            }
 5917            for (buffer, edits) in linked_edits {
 5918                buffer.update(cx, |buffer, cx| {
 5919                    let snapshot = buffer.snapshot();
 5920                    let edits = edits
 5921                        .into_iter()
 5922                        .map(|(range, text)| {
 5923                            use text::ToPoint as TP;
 5924                            let end_point = TP::to_point(&range.end, &snapshot);
 5925                            let start_point = TP::to_point(&range.start, &snapshot);
 5926                            (start_point..end_point, text)
 5927                        })
 5928                        .sorted_by_key(|(range, _)| range.start);
 5929                    buffer.edit(edits, None, cx);
 5930                })
 5931            }
 5932
 5933            editor.refresh_inline_completion(true, false, window, cx);
 5934        });
 5935        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5936
 5937        let show_new_completions_on_confirm = completion
 5938            .confirm
 5939            .as_ref()
 5940            .map_or(false, |confirm| confirm(intent, window, cx));
 5941        if show_new_completions_on_confirm {
 5942            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5943        }
 5944
 5945        let provider = self.completion_provider.as_ref()?;
 5946        drop(completion);
 5947        let apply_edits = provider.apply_additional_edits_for_completion(
 5948            buffer_handle,
 5949            completions_menu.completions.clone(),
 5950            candidate_id,
 5951            true,
 5952            cx,
 5953        );
 5954
 5955        let editor_settings = EditorSettings::get_global(cx);
 5956        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5957            // After the code completion is finished, users often want to know what signatures are needed.
 5958            // so we should automatically call signature_help
 5959            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5960        }
 5961
 5962        Some(cx.foreground_executor().spawn(async move {
 5963            apply_edits.await?;
 5964            Ok(())
 5965        }))
 5966    }
 5967
 5968    pub fn toggle_code_actions(
 5969        &mut self,
 5970        action: &ToggleCodeActions,
 5971        window: &mut Window,
 5972        cx: &mut Context<Self>,
 5973    ) {
 5974        let quick_launch = action.quick_launch;
 5975        let mut context_menu = self.context_menu.borrow_mut();
 5976        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5977            if code_actions.deployed_from == action.deployed_from {
 5978                // Toggle if we're selecting the same one
 5979                *context_menu = None;
 5980                cx.notify();
 5981                return;
 5982            } else {
 5983                // Otherwise, clear it and start a new one
 5984                *context_menu = None;
 5985                cx.notify();
 5986            }
 5987        }
 5988        drop(context_menu);
 5989        let snapshot = self.snapshot(window, cx);
 5990        let deployed_from = action.deployed_from.clone();
 5991        let action = action.clone();
 5992        self.completion_tasks.clear();
 5993        self.discard_inline_completion(false, cx);
 5994
 5995        let multibuffer_point = match &action.deployed_from {
 5996            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5997                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5998            }
 5999            _ => self.selections.newest::<Point>(cx).head(),
 6000        };
 6001        let Some((buffer, buffer_row)) = snapshot
 6002            .buffer_snapshot
 6003            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6004            .and_then(|(buffer_snapshot, range)| {
 6005                self.buffer()
 6006                    .read(cx)
 6007                    .buffer(buffer_snapshot.remote_id())
 6008                    .map(|buffer| (buffer, range.start.row))
 6009            })
 6010        else {
 6011            return;
 6012        };
 6013        let buffer_id = buffer.read(cx).remote_id();
 6014        let tasks = self
 6015            .tasks
 6016            .get(&(buffer_id, buffer_row))
 6017            .map(|t| Arc::new(t.to_owned()));
 6018
 6019        if !self.focus_handle.is_focused(window) {
 6020            return;
 6021        }
 6022        let project = self.project.clone();
 6023
 6024        let code_actions_task = match deployed_from {
 6025            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6026            _ => self.code_actions(buffer_row, window, cx),
 6027        };
 6028
 6029        let runnable_task = match deployed_from {
 6030            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6031            _ => {
 6032                let mut task_context_task = Task::ready(None);
 6033                if let Some(tasks) = &tasks {
 6034                    if let Some(project) = project {
 6035                        task_context_task =
 6036                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6037                    }
 6038                }
 6039
 6040                cx.spawn_in(window, {
 6041                    let buffer = buffer.clone();
 6042                    async move |editor, cx| {
 6043                        let task_context = task_context_task.await;
 6044
 6045                        let resolved_tasks =
 6046                            tasks
 6047                                .zip(task_context.clone())
 6048                                .map(|(tasks, task_context)| ResolvedTasks {
 6049                                    templates: tasks.resolve(&task_context).collect(),
 6050                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6051                                        multibuffer_point.row,
 6052                                        tasks.column,
 6053                                    )),
 6054                                });
 6055                        let debug_scenarios = editor
 6056                            .update(cx, |editor, cx| {
 6057                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6058                            })?
 6059                            .await;
 6060                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6061                    }
 6062                })
 6063            }
 6064        };
 6065
 6066        cx.spawn_in(window, async move |editor, cx| {
 6067            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6068            let code_actions = code_actions_task.await;
 6069            let spawn_straight_away = quick_launch
 6070                && resolved_tasks
 6071                    .as_ref()
 6072                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6073                && code_actions
 6074                    .as_ref()
 6075                    .map_or(true, |actions| actions.is_empty())
 6076                && debug_scenarios.is_empty();
 6077
 6078            editor.update_in(cx, |editor, window, cx| {
 6079                crate::hover_popover::hide_hover(editor, cx);
 6080                let actions = CodeActionContents::new(
 6081                    resolved_tasks,
 6082                    code_actions,
 6083                    debug_scenarios,
 6084                    task_context.unwrap_or_default(),
 6085                );
 6086
 6087                // Don't show the menu if there are no actions available
 6088                if actions.is_empty() {
 6089                    cx.notify();
 6090                    return Task::ready(Ok(()));
 6091                }
 6092
 6093                *editor.context_menu.borrow_mut() =
 6094                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6095                        buffer,
 6096                        actions,
 6097                        selected_item: Default::default(),
 6098                        scroll_handle: UniformListScrollHandle::default(),
 6099                        deployed_from,
 6100                    }));
 6101                cx.notify();
 6102                if spawn_straight_away {
 6103                    if let Some(task) = editor.confirm_code_action(
 6104                        &ConfirmCodeAction { item_ix: Some(0) },
 6105                        window,
 6106                        cx,
 6107                    ) {
 6108                        return task;
 6109                    }
 6110                }
 6111
 6112                Task::ready(Ok(()))
 6113            })
 6114        })
 6115        .detach_and_log_err(cx);
 6116    }
 6117
 6118    fn debug_scenarios(
 6119        &mut self,
 6120        resolved_tasks: &Option<ResolvedTasks>,
 6121        buffer: &Entity<Buffer>,
 6122        cx: &mut App,
 6123    ) -> Task<Vec<task::DebugScenario>> {
 6124        maybe!({
 6125            let project = self.project.as_ref()?;
 6126            let dap_store = project.read(cx).dap_store();
 6127            let mut scenarios = vec![];
 6128            let resolved_tasks = resolved_tasks.as_ref()?;
 6129            let buffer = buffer.read(cx);
 6130            let language = buffer.language()?;
 6131            let file = buffer.file();
 6132            let debug_adapter = language_settings(language.name().into(), file, cx)
 6133                .debuggers
 6134                .first()
 6135                .map(SharedString::from)
 6136                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6137
 6138            dap_store.update(cx, |dap_store, cx| {
 6139                for (_, task) in &resolved_tasks.templates {
 6140                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6141                        task.original_task().clone(),
 6142                        debug_adapter.clone().into(),
 6143                        task.display_label().to_owned().into(),
 6144                        cx,
 6145                    );
 6146                    scenarios.push(maybe_scenario);
 6147                }
 6148            });
 6149            Some(cx.background_spawn(async move {
 6150                let scenarios = futures::future::join_all(scenarios)
 6151                    .await
 6152                    .into_iter()
 6153                    .flatten()
 6154                    .collect::<Vec<_>>();
 6155                scenarios
 6156            }))
 6157        })
 6158        .unwrap_or_else(|| Task::ready(vec![]))
 6159    }
 6160
 6161    fn code_actions(
 6162        &mut self,
 6163        buffer_row: u32,
 6164        window: &mut Window,
 6165        cx: &mut Context<Self>,
 6166    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6167        let mut task = self.code_actions_task.take();
 6168        cx.spawn_in(window, async move |editor, cx| {
 6169            while let Some(prev_task) = task {
 6170                prev_task.await.log_err();
 6171                task = editor
 6172                    .update(cx, |this, _| this.code_actions_task.take())
 6173                    .ok()?;
 6174            }
 6175
 6176            editor
 6177                .update(cx, |editor, cx| {
 6178                    editor
 6179                        .available_code_actions
 6180                        .clone()
 6181                        .and_then(|(location, code_actions)| {
 6182                            let snapshot = location.buffer.read(cx).snapshot();
 6183                            let point_range = location.range.to_point(&snapshot);
 6184                            let point_range = point_range.start.row..=point_range.end.row;
 6185                            if point_range.contains(&buffer_row) {
 6186                                Some(code_actions)
 6187                            } else {
 6188                                None
 6189                            }
 6190                        })
 6191                })
 6192                .ok()
 6193                .flatten()
 6194        })
 6195    }
 6196
 6197    pub fn confirm_code_action(
 6198        &mut self,
 6199        action: &ConfirmCodeAction,
 6200        window: &mut Window,
 6201        cx: &mut Context<Self>,
 6202    ) -> Option<Task<Result<()>>> {
 6203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6204
 6205        let actions_menu =
 6206            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6207                menu
 6208            } else {
 6209                return None;
 6210            };
 6211
 6212        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6213        let action = actions_menu.actions.get(action_ix)?;
 6214        let title = action.label();
 6215        let buffer = actions_menu.buffer;
 6216        let workspace = self.workspace()?;
 6217
 6218        match action {
 6219            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6220                workspace.update(cx, |workspace, cx| {
 6221                    workspace.schedule_resolved_task(
 6222                        task_source_kind,
 6223                        resolved_task,
 6224                        false,
 6225                        window,
 6226                        cx,
 6227                    );
 6228
 6229                    Some(Task::ready(Ok(())))
 6230                })
 6231            }
 6232            CodeActionsItem::CodeAction {
 6233                excerpt_id,
 6234                action,
 6235                provider,
 6236            } => {
 6237                let apply_code_action =
 6238                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6239                let workspace = workspace.downgrade();
 6240                Some(cx.spawn_in(window, async move |editor, cx| {
 6241                    let project_transaction = apply_code_action.await?;
 6242                    Self::open_project_transaction(
 6243                        &editor,
 6244                        workspace,
 6245                        project_transaction,
 6246                        title,
 6247                        cx,
 6248                    )
 6249                    .await
 6250                }))
 6251            }
 6252            CodeActionsItem::DebugScenario(scenario) => {
 6253                let context = actions_menu.actions.context.clone();
 6254
 6255                workspace.update(cx, |workspace, cx| {
 6256                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6257                    workspace.start_debug_session(
 6258                        scenario,
 6259                        context,
 6260                        Some(buffer),
 6261                        None,
 6262                        window,
 6263                        cx,
 6264                    );
 6265                });
 6266                Some(Task::ready(Ok(())))
 6267            }
 6268        }
 6269    }
 6270
 6271    pub async fn open_project_transaction(
 6272        this: &WeakEntity<Editor>,
 6273        workspace: WeakEntity<Workspace>,
 6274        transaction: ProjectTransaction,
 6275        title: String,
 6276        cx: &mut AsyncWindowContext,
 6277    ) -> Result<()> {
 6278        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6279        cx.update(|_, cx| {
 6280            entries.sort_unstable_by_key(|(buffer, _)| {
 6281                buffer.read(cx).file().map(|f| f.path().clone())
 6282            });
 6283        })?;
 6284
 6285        // If the project transaction's edits are all contained within this editor, then
 6286        // avoid opening a new editor to display them.
 6287
 6288        if let Some((buffer, transaction)) = entries.first() {
 6289            if entries.len() == 1 {
 6290                let excerpt = this.update(cx, |editor, cx| {
 6291                    editor
 6292                        .buffer()
 6293                        .read(cx)
 6294                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6295                })?;
 6296                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6297                    if excerpted_buffer == *buffer {
 6298                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6299                            let excerpt_range = excerpt_range.to_offset(buffer);
 6300                            buffer
 6301                                .edited_ranges_for_transaction::<usize>(transaction)
 6302                                .all(|range| {
 6303                                    excerpt_range.start <= range.start
 6304                                        && excerpt_range.end >= range.end
 6305                                })
 6306                        })?;
 6307
 6308                        if all_edits_within_excerpt {
 6309                            return Ok(());
 6310                        }
 6311                    }
 6312                }
 6313            }
 6314        } else {
 6315            return Ok(());
 6316        }
 6317
 6318        let mut ranges_to_highlight = Vec::new();
 6319        let excerpt_buffer = cx.new(|cx| {
 6320            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6321            for (buffer_handle, transaction) in &entries {
 6322                let edited_ranges = buffer_handle
 6323                    .read(cx)
 6324                    .edited_ranges_for_transaction::<Point>(transaction)
 6325                    .collect::<Vec<_>>();
 6326                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6327                    PathKey::for_buffer(buffer_handle, cx),
 6328                    buffer_handle.clone(),
 6329                    edited_ranges,
 6330                    DEFAULT_MULTIBUFFER_CONTEXT,
 6331                    cx,
 6332                );
 6333
 6334                ranges_to_highlight.extend(ranges);
 6335            }
 6336            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6337            multibuffer
 6338        })?;
 6339
 6340        workspace.update_in(cx, |workspace, window, cx| {
 6341            let project = workspace.project().clone();
 6342            let editor =
 6343                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6344            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6345            editor.update(cx, |editor, cx| {
 6346                editor.highlight_background::<Self>(
 6347                    &ranges_to_highlight,
 6348                    |theme| theme.colors().editor_highlighted_line_background,
 6349                    cx,
 6350                );
 6351            });
 6352        })?;
 6353
 6354        Ok(())
 6355    }
 6356
 6357    pub fn clear_code_action_providers(&mut self) {
 6358        self.code_action_providers.clear();
 6359        self.available_code_actions.take();
 6360    }
 6361
 6362    pub fn add_code_action_provider(
 6363        &mut self,
 6364        provider: Rc<dyn CodeActionProvider>,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) {
 6368        if self
 6369            .code_action_providers
 6370            .iter()
 6371            .any(|existing_provider| existing_provider.id() == provider.id())
 6372        {
 6373            return;
 6374        }
 6375
 6376        self.code_action_providers.push(provider);
 6377        self.refresh_code_actions(window, cx);
 6378    }
 6379
 6380    pub fn remove_code_action_provider(
 6381        &mut self,
 6382        id: Arc<str>,
 6383        window: &mut Window,
 6384        cx: &mut Context<Self>,
 6385    ) {
 6386        self.code_action_providers
 6387            .retain(|provider| provider.id() != id);
 6388        self.refresh_code_actions(window, cx);
 6389    }
 6390
 6391    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6392        !self.code_action_providers.is_empty()
 6393            && EditorSettings::get_global(cx).toolbar.code_actions
 6394    }
 6395
 6396    pub fn has_available_code_actions(&self) -> bool {
 6397        self.available_code_actions
 6398            .as_ref()
 6399            .is_some_and(|(_, actions)| !actions.is_empty())
 6400    }
 6401
 6402    fn render_inline_code_actions(
 6403        &self,
 6404        icon_size: ui::IconSize,
 6405        display_row: DisplayRow,
 6406        is_active: bool,
 6407        cx: &mut Context<Self>,
 6408    ) -> AnyElement {
 6409        let show_tooltip = !self.context_menu_visible();
 6410        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6411            .icon_size(icon_size)
 6412            .shape(ui::IconButtonShape::Square)
 6413            .style(ButtonStyle::Transparent)
 6414            .icon_color(ui::Color::Hidden)
 6415            .toggle_state(is_active)
 6416            .when(show_tooltip, |this| {
 6417                this.tooltip({
 6418                    let focus_handle = self.focus_handle.clone();
 6419                    move |window, cx| {
 6420                        Tooltip::for_action_in(
 6421                            "Toggle Code Actions",
 6422                            &ToggleCodeActions {
 6423                                deployed_from: None,
 6424                                quick_launch: false,
 6425                            },
 6426                            &focus_handle,
 6427                            window,
 6428                            cx,
 6429                        )
 6430                    }
 6431                })
 6432            })
 6433            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6434                window.focus(&editor.focus_handle(cx));
 6435                editor.toggle_code_actions(
 6436                    &crate::actions::ToggleCodeActions {
 6437                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6438                            display_row,
 6439                        )),
 6440                        quick_launch: false,
 6441                    },
 6442                    window,
 6443                    cx,
 6444                );
 6445            }))
 6446            .into_any_element()
 6447    }
 6448
 6449    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6450        &self.context_menu
 6451    }
 6452
 6453    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6454        let newest_selection = self.selections.newest_anchor().clone();
 6455        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6456        let buffer = self.buffer.read(cx);
 6457        if newest_selection.head().diff_base_anchor.is_some() {
 6458            return None;
 6459        }
 6460        let (start_buffer, start) =
 6461            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6462        let (end_buffer, end) =
 6463            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6464        if start_buffer != end_buffer {
 6465            return None;
 6466        }
 6467
 6468        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6469            cx.background_executor()
 6470                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6471                .await;
 6472
 6473            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6474                let providers = this.code_action_providers.clone();
 6475                let tasks = this
 6476                    .code_action_providers
 6477                    .iter()
 6478                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6479                    .collect::<Vec<_>>();
 6480                (providers, tasks)
 6481            })?;
 6482
 6483            let mut actions = Vec::new();
 6484            for (provider, provider_actions) in
 6485                providers.into_iter().zip(future::join_all(tasks).await)
 6486            {
 6487                if let Some(provider_actions) = provider_actions.log_err() {
 6488                    actions.extend(provider_actions.into_iter().map(|action| {
 6489                        AvailableCodeAction {
 6490                            excerpt_id: newest_selection.start.excerpt_id,
 6491                            action,
 6492                            provider: provider.clone(),
 6493                        }
 6494                    }));
 6495                }
 6496            }
 6497
 6498            this.update(cx, |this, cx| {
 6499                this.available_code_actions = if actions.is_empty() {
 6500                    None
 6501                } else {
 6502                    Some((
 6503                        Location {
 6504                            buffer: start_buffer,
 6505                            range: start..end,
 6506                        },
 6507                        actions.into(),
 6508                    ))
 6509                };
 6510                cx.notify();
 6511            })
 6512        }));
 6513        None
 6514    }
 6515
 6516    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6517        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6518            self.show_git_blame_inline = false;
 6519
 6520            self.show_git_blame_inline_delay_task =
 6521                Some(cx.spawn_in(window, async move |this, cx| {
 6522                    cx.background_executor().timer(delay).await;
 6523
 6524                    this.update(cx, |this, cx| {
 6525                        this.show_git_blame_inline = true;
 6526                        cx.notify();
 6527                    })
 6528                    .log_err();
 6529                }));
 6530        }
 6531    }
 6532
 6533    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6534        let snapshot = self.snapshot(window, cx);
 6535        let cursor = self.selections.newest::<Point>(cx).head();
 6536        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6537        else {
 6538            return;
 6539        };
 6540
 6541        let Some(blame) = self.blame.as_ref() else {
 6542            return;
 6543        };
 6544
 6545        let row_info = RowInfo {
 6546            buffer_id: Some(buffer.remote_id()),
 6547            buffer_row: Some(point.row),
 6548            ..Default::default()
 6549        };
 6550        let Some(blame_entry) = blame
 6551            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6552            .flatten()
 6553        else {
 6554            return;
 6555        };
 6556
 6557        let anchor = self.selections.newest_anchor().head();
 6558        let position = self.to_pixel_point(anchor, &snapshot, window);
 6559        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6560            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6561        };
 6562    }
 6563
 6564    fn show_blame_popover(
 6565        &mut self,
 6566        blame_entry: &BlameEntry,
 6567        position: gpui::Point<Pixels>,
 6568        ignore_timeout: bool,
 6569        cx: &mut Context<Self>,
 6570    ) {
 6571        if let Some(state) = &mut self.inline_blame_popover {
 6572            state.hide_task.take();
 6573        } else {
 6574            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6575            let blame_entry = blame_entry.clone();
 6576            let show_task = cx.spawn(async move |editor, cx| {
 6577                if !ignore_timeout {
 6578                    cx.background_executor()
 6579                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6580                        .await;
 6581                }
 6582                editor
 6583                    .update(cx, |editor, cx| {
 6584                        editor.inline_blame_popover_show_task.take();
 6585                        let Some(blame) = editor.blame.as_ref() else {
 6586                            return;
 6587                        };
 6588                        let blame = blame.read(cx);
 6589                        let details = blame.details_for_entry(&blame_entry);
 6590                        let markdown = cx.new(|cx| {
 6591                            Markdown::new(
 6592                                details
 6593                                    .as_ref()
 6594                                    .map(|message| message.message.clone())
 6595                                    .unwrap_or_default(),
 6596                                None,
 6597                                None,
 6598                                cx,
 6599                            )
 6600                        });
 6601                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6602                            position,
 6603                            hide_task: None,
 6604                            popover_bounds: None,
 6605                            popover_state: InlineBlamePopoverState {
 6606                                scroll_handle: ScrollHandle::new(),
 6607                                commit_message: details,
 6608                                markdown,
 6609                            },
 6610                            keyboard_grace: ignore_timeout,
 6611                        });
 6612                        cx.notify();
 6613                    })
 6614                    .ok();
 6615            });
 6616            self.inline_blame_popover_show_task = Some(show_task);
 6617        }
 6618    }
 6619
 6620    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6621        self.inline_blame_popover_show_task.take();
 6622        if let Some(state) = &mut self.inline_blame_popover {
 6623            let hide_task = cx.spawn(async move |editor, cx| {
 6624                cx.background_executor()
 6625                    .timer(std::time::Duration::from_millis(100))
 6626                    .await;
 6627                editor
 6628                    .update(cx, |editor, cx| {
 6629                        editor.inline_blame_popover.take();
 6630                        cx.notify();
 6631                    })
 6632                    .ok();
 6633            });
 6634            state.hide_task = Some(hide_task);
 6635        }
 6636    }
 6637
 6638    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6639        if self.pending_rename.is_some() {
 6640            return None;
 6641        }
 6642
 6643        let provider = self.semantics_provider.clone()?;
 6644        let buffer = self.buffer.read(cx);
 6645        let newest_selection = self.selections.newest_anchor().clone();
 6646        let cursor_position = newest_selection.head();
 6647        let (cursor_buffer, cursor_buffer_position) =
 6648            buffer.text_anchor_for_position(cursor_position, cx)?;
 6649        let (tail_buffer, tail_buffer_position) =
 6650            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6651        if cursor_buffer != tail_buffer {
 6652            return None;
 6653        }
 6654
 6655        let snapshot = cursor_buffer.read(cx).snapshot();
 6656        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6657        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6658        if start_word_range != end_word_range {
 6659            self.document_highlights_task.take();
 6660            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6661            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6662            return None;
 6663        }
 6664
 6665        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6666        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6667            cx.background_executor()
 6668                .timer(Duration::from_millis(debounce))
 6669                .await;
 6670
 6671            let highlights = if let Some(highlights) = cx
 6672                .update(|cx| {
 6673                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6674                })
 6675                .ok()
 6676                .flatten()
 6677            {
 6678                highlights.await.log_err()
 6679            } else {
 6680                None
 6681            };
 6682
 6683            if let Some(highlights) = highlights {
 6684                this.update(cx, |this, cx| {
 6685                    if this.pending_rename.is_some() {
 6686                        return;
 6687                    }
 6688
 6689                    let buffer_id = cursor_position.buffer_id;
 6690                    let buffer = this.buffer.read(cx);
 6691                    if !buffer
 6692                        .text_anchor_for_position(cursor_position, cx)
 6693                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6694                    {
 6695                        return;
 6696                    }
 6697
 6698                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6699                    let mut write_ranges = Vec::new();
 6700                    let mut read_ranges = Vec::new();
 6701                    for highlight in highlights {
 6702                        for (excerpt_id, excerpt_range) in
 6703                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6704                        {
 6705                            let start = highlight
 6706                                .range
 6707                                .start
 6708                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6709                            let end = highlight
 6710                                .range
 6711                                .end
 6712                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6713                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6714                                continue;
 6715                            }
 6716
 6717                            let range = Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: start,
 6721                                diff_base_anchor: None,
 6722                            }..Anchor {
 6723                                buffer_id,
 6724                                excerpt_id,
 6725                                text_anchor: end,
 6726                                diff_base_anchor: None,
 6727                            };
 6728                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6729                                write_ranges.push(range);
 6730                            } else {
 6731                                read_ranges.push(range);
 6732                            }
 6733                        }
 6734                    }
 6735
 6736                    this.highlight_background::<DocumentHighlightRead>(
 6737                        &read_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_read_background,
 6739                        cx,
 6740                    );
 6741                    this.highlight_background::<DocumentHighlightWrite>(
 6742                        &write_ranges,
 6743                        |theme| theme.colors().editor_document_highlight_write_background,
 6744                        cx,
 6745                    );
 6746                    cx.notify();
 6747                })
 6748                .log_err();
 6749            }
 6750        }));
 6751        None
 6752    }
 6753
 6754    fn prepare_highlight_query_from_selection(
 6755        &mut self,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Option<(String, Range<Anchor>)> {
 6758        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6759            return None;
 6760        }
 6761        if !EditorSettings::get_global(cx).selection_highlight {
 6762            return None;
 6763        }
 6764        if self.selections.count() != 1 || self.selections.line_mode {
 6765            return None;
 6766        }
 6767        let selection = self.selections.newest::<Point>(cx);
 6768        if selection.is_empty() || selection.start.row != selection.end.row {
 6769            return None;
 6770        }
 6771        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6772        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6773        let query = multi_buffer_snapshot
 6774            .text_for_range(selection_anchor_range.clone())
 6775            .collect::<String>();
 6776        if query.trim().is_empty() {
 6777            return None;
 6778        }
 6779        Some((query, selection_anchor_range))
 6780    }
 6781
 6782    fn update_selection_occurrence_highlights(
 6783        &mut self,
 6784        query_text: String,
 6785        query_range: Range<Anchor>,
 6786        multi_buffer_range_to_query: Range<Point>,
 6787        use_debounce: bool,
 6788        window: &mut Window,
 6789        cx: &mut Context<Editor>,
 6790    ) -> Task<()> {
 6791        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6792        cx.spawn_in(window, async move |editor, cx| {
 6793            if use_debounce {
 6794                cx.background_executor()
 6795                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6796                    .await;
 6797            }
 6798            let match_task = cx.background_spawn(async move {
 6799                let buffer_ranges = multi_buffer_snapshot
 6800                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6801                    .into_iter()
 6802                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6803                let mut match_ranges = Vec::new();
 6804                let Ok(regex) = project::search::SearchQuery::text(
 6805                    query_text.clone(),
 6806                    false,
 6807                    false,
 6808                    false,
 6809                    Default::default(),
 6810                    Default::default(),
 6811                    false,
 6812                    None,
 6813                ) else {
 6814                    return Vec::default();
 6815                };
 6816                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6817                    match_ranges.extend(
 6818                        regex
 6819                            .search(&buffer_snapshot, Some(search_range.clone()))
 6820                            .await
 6821                            .into_iter()
 6822                            .filter_map(|match_range| {
 6823                                let match_start = buffer_snapshot
 6824                                    .anchor_after(search_range.start + match_range.start);
 6825                                let match_end = buffer_snapshot
 6826                                    .anchor_before(search_range.start + match_range.end);
 6827                                let match_anchor_range = Anchor::range_in_buffer(
 6828                                    excerpt_id,
 6829                                    buffer_snapshot.remote_id(),
 6830                                    match_start..match_end,
 6831                                );
 6832                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6833                            }),
 6834                    );
 6835                }
 6836                match_ranges
 6837            });
 6838            let match_ranges = match_task.await;
 6839            editor
 6840                .update_in(cx, |editor, _, cx| {
 6841                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6842                    if !match_ranges.is_empty() {
 6843                        editor.highlight_background::<SelectedTextHighlight>(
 6844                            &match_ranges,
 6845                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6846                            cx,
 6847                        )
 6848                    }
 6849                })
 6850                .log_err();
 6851        })
 6852    }
 6853
 6854    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6855        struct NewlineFold;
 6856        let type_id = std::any::TypeId::of::<NewlineFold>();
 6857        if !self.mode.is_single_line() {
 6858            return;
 6859        }
 6860        let snapshot = self.snapshot(window, cx);
 6861        if snapshot.buffer_snapshot.max_point().row == 0 {
 6862            return;
 6863        }
 6864        let task = cx.background_spawn(async move {
 6865            let new_newlines = snapshot
 6866                .buffer_chars_at(0)
 6867                .filter_map(|(c, i)| {
 6868                    if c == '\n' {
 6869                        Some(
 6870                            snapshot.buffer_snapshot.anchor_after(i)
 6871                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6872                        )
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878            let existing_newlines = snapshot
 6879                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6880                .filter_map(|fold| {
 6881                    if fold.placeholder.type_tag == Some(type_id) {
 6882                        Some(fold.range.start..fold.range.end)
 6883                    } else {
 6884                        None
 6885                    }
 6886                })
 6887                .collect::<Vec<_>>();
 6888
 6889            (new_newlines, existing_newlines)
 6890        });
 6891        self.folding_newlines = cx.spawn(async move |this, cx| {
 6892            let (new_newlines, existing_newlines) = task.await;
 6893            if new_newlines == existing_newlines {
 6894                return;
 6895            }
 6896            let placeholder = FoldPlaceholder {
 6897                render: Arc::new(move |_, _, cx| {
 6898                    div()
 6899                        .bg(cx.theme().status().hint_background)
 6900                        .border_b_1()
 6901                        .size_full()
 6902                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6903                        .border_color(cx.theme().status().hint)
 6904                        .child("\\n")
 6905                        .into_any()
 6906                }),
 6907                constrain_width: false,
 6908                merge_adjacent: false,
 6909                type_tag: Some(type_id),
 6910            };
 6911            let creases = new_newlines
 6912                .into_iter()
 6913                .map(|range| Crease::simple(range, placeholder.clone()))
 6914                .collect();
 6915            this.update(cx, |this, cx| {
 6916                this.display_map.update(cx, |display_map, cx| {
 6917                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6918                    display_map.fold(creases, cx);
 6919                });
 6920            })
 6921            .ok();
 6922        });
 6923    }
 6924
 6925    fn refresh_selected_text_highlights(
 6926        &mut self,
 6927        on_buffer_edit: bool,
 6928        window: &mut Window,
 6929        cx: &mut Context<Editor>,
 6930    ) {
 6931        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6932        else {
 6933            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6934            self.quick_selection_highlight_task.take();
 6935            self.debounced_selection_highlight_task.take();
 6936            return;
 6937        };
 6938        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6939        if on_buffer_edit
 6940            || self
 6941                .quick_selection_highlight_task
 6942                .as_ref()
 6943                .map_or(true, |(prev_anchor_range, _)| {
 6944                    prev_anchor_range != &query_range
 6945                })
 6946        {
 6947            let multi_buffer_visible_start = self
 6948                .scroll_manager
 6949                .anchor()
 6950                .anchor
 6951                .to_point(&multi_buffer_snapshot);
 6952            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6953                multi_buffer_visible_start
 6954                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6955                Bias::Left,
 6956            );
 6957            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6958            self.quick_selection_highlight_task = Some((
 6959                query_range.clone(),
 6960                self.update_selection_occurrence_highlights(
 6961                    query_text.clone(),
 6962                    query_range.clone(),
 6963                    multi_buffer_visible_range,
 6964                    false,
 6965                    window,
 6966                    cx,
 6967                ),
 6968            ));
 6969        }
 6970        if on_buffer_edit
 6971            || self
 6972                .debounced_selection_highlight_task
 6973                .as_ref()
 6974                .map_or(true, |(prev_anchor_range, _)| {
 6975                    prev_anchor_range != &query_range
 6976                })
 6977        {
 6978            let multi_buffer_start = multi_buffer_snapshot
 6979                .anchor_before(0)
 6980                .to_point(&multi_buffer_snapshot);
 6981            let multi_buffer_end = multi_buffer_snapshot
 6982                .anchor_after(multi_buffer_snapshot.len())
 6983                .to_point(&multi_buffer_snapshot);
 6984            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6985            self.debounced_selection_highlight_task = Some((
 6986                query_range.clone(),
 6987                self.update_selection_occurrence_highlights(
 6988                    query_text,
 6989                    query_range,
 6990                    multi_buffer_full_range,
 6991                    true,
 6992                    window,
 6993                    cx,
 6994                ),
 6995            ));
 6996        }
 6997    }
 6998
 6999    pub fn refresh_inline_completion(
 7000        &mut self,
 7001        debounce: bool,
 7002        user_requested: bool,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) -> Option<()> {
 7006        let provider = self.edit_prediction_provider()?;
 7007        let cursor = self.selections.newest_anchor().head();
 7008        let (buffer, cursor_buffer_position) =
 7009            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7010
 7011        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7012            self.discard_inline_completion(false, cx);
 7013            return None;
 7014        }
 7015
 7016        if !user_requested
 7017            && (!self.should_show_edit_predictions()
 7018                || !self.is_focused(window)
 7019                || buffer.read(cx).is_empty())
 7020        {
 7021            self.discard_inline_completion(false, cx);
 7022            return None;
 7023        }
 7024
 7025        self.update_visible_inline_completion(window, cx);
 7026        provider.refresh(
 7027            self.project.clone(),
 7028            buffer,
 7029            cursor_buffer_position,
 7030            debounce,
 7031            cx,
 7032        );
 7033        Some(())
 7034    }
 7035
 7036    fn show_edit_predictions_in_menu(&self) -> bool {
 7037        match self.edit_prediction_settings {
 7038            EditPredictionSettings::Disabled => false,
 7039            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7040        }
 7041    }
 7042
 7043    pub fn edit_predictions_enabled(&self) -> bool {
 7044        match self.edit_prediction_settings {
 7045            EditPredictionSettings::Disabled => false,
 7046            EditPredictionSettings::Enabled { .. } => true,
 7047        }
 7048    }
 7049
 7050    fn edit_prediction_requires_modifier(&self) -> bool {
 7051        match self.edit_prediction_settings {
 7052            EditPredictionSettings::Disabled => false,
 7053            EditPredictionSettings::Enabled {
 7054                preview_requires_modifier,
 7055                ..
 7056            } => preview_requires_modifier,
 7057        }
 7058    }
 7059
 7060    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7061        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7062            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7063        } else {
 7064            let selection = self.selections.newest_anchor();
 7065            let cursor = selection.head();
 7066
 7067            if let Some((buffer, cursor_buffer_position)) =
 7068                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7069            {
 7070                self.edit_prediction_settings =
 7071                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7072            }
 7073        }
 7074    }
 7075
 7076    fn edit_prediction_settings_at_position(
 7077        &self,
 7078        buffer: &Entity<Buffer>,
 7079        buffer_position: language::Anchor,
 7080        cx: &App,
 7081    ) -> EditPredictionSettings {
 7082        if !self.mode.is_full()
 7083            || !self.show_inline_completions_override.unwrap_or(true)
 7084            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7085        {
 7086            return EditPredictionSettings::Disabled;
 7087        }
 7088
 7089        let buffer = buffer.read(cx);
 7090
 7091        let file = buffer.file();
 7092
 7093        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7094            return EditPredictionSettings::Disabled;
 7095        };
 7096
 7097        let by_provider = matches!(
 7098            self.menu_inline_completions_policy,
 7099            MenuInlineCompletionsPolicy::ByProvider
 7100        );
 7101
 7102        let show_in_menu = by_provider
 7103            && self
 7104                .edit_prediction_provider
 7105                .as_ref()
 7106                .map_or(false, |provider| {
 7107                    provider.provider.show_completions_in_menu()
 7108                });
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_inline_completion(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_inline_completion(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_inline_completion(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_inline_completion() {
 7196            self.refresh_inline_completion(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_inline_completion(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_inline_completion() {
 7233            self.cycle_inline_completion(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_inline_completion(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_inline_completion() {
 7251            self.cycle_inline_completion(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_inline_completion(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        self.report_inline_completion_event(
 7277            active_inline_completion.completion_id.clone(),
 7278            true,
 7279            cx,
 7280        );
 7281
 7282        match &active_inline_completion.completion {
 7283            InlineCompletion::Move { target, .. } => {
 7284                let target = *target;
 7285
 7286                if let Some(position_map) = &self.last_position_map {
 7287                    if position_map
 7288                        .visible_row_range
 7289                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7290                        || !self.edit_prediction_requires_modifier()
 7291                    {
 7292                        self.unfold_ranges(&[target..target], true, false, cx);
 7293                        // Note that this is also done in vim's handler of the Tab action.
 7294                        self.change_selections(
 7295                            SelectionEffects::scroll(Autoscroll::newest()),
 7296                            window,
 7297                            cx,
 7298                            |selections| {
 7299                                selections.select_anchor_ranges([target..target]);
 7300                            },
 7301                        );
 7302                        self.clear_row_highlights::<EditPredictionPreview>();
 7303
 7304                        self.edit_prediction_preview
 7305                            .set_previous_scroll_position(None);
 7306                    } else {
 7307                        self.edit_prediction_preview
 7308                            .set_previous_scroll_position(Some(
 7309                                position_map.snapshot.scroll_anchor,
 7310                            ));
 7311
 7312                        self.highlight_rows::<EditPredictionPreview>(
 7313                            target..target,
 7314                            cx.theme().colors().editor_highlighted_line_background,
 7315                            RowHighlightOptions {
 7316                                autoscroll: true,
 7317                                ..Default::default()
 7318                            },
 7319                            cx,
 7320                        );
 7321                        self.request_autoscroll(Autoscroll::fit(), cx);
 7322                    }
 7323                }
 7324            }
 7325            InlineCompletion::Edit { edits, .. } => {
 7326                if let Some(provider) = self.edit_prediction_provider() {
 7327                    provider.accept(cx);
 7328                }
 7329
 7330                // Store the transaction ID and selections before applying the edit
 7331                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7332
 7333                let snapshot = self.buffer.read(cx).snapshot(cx);
 7334                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7335
 7336                self.buffer.update(cx, |buffer, cx| {
 7337                    buffer.edit(edits.iter().cloned(), None, cx)
 7338                });
 7339
 7340                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7341                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7342                });
 7343
 7344                let selections = self.selections.disjoint_anchors();
 7345                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7346                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7347                    if has_new_transaction {
 7348                        self.selection_history
 7349                            .insert_transaction(transaction_id_now, selections);
 7350                    }
 7351                }
 7352
 7353                self.update_visible_inline_completion(window, cx);
 7354                if self.active_inline_completion.is_none() {
 7355                    self.refresh_inline_completion(true, true, window, cx);
 7356                }
 7357
 7358                cx.notify();
 7359            }
 7360        }
 7361
 7362        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7363    }
 7364
 7365    pub fn accept_partial_inline_completion(
 7366        &mut self,
 7367        _: &AcceptPartialEditPrediction,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) {
 7371        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7372            return;
 7373        };
 7374        if self.selections.count() != 1 {
 7375            return;
 7376        }
 7377
 7378        self.report_inline_completion_event(
 7379            active_inline_completion.completion_id.clone(),
 7380            true,
 7381            cx,
 7382        );
 7383
 7384        match &active_inline_completion.completion {
 7385            InlineCompletion::Move { target, .. } => {
 7386                let target = *target;
 7387                self.change_selections(
 7388                    SelectionEffects::scroll(Autoscroll::newest()),
 7389                    window,
 7390                    cx,
 7391                    |selections| {
 7392                        selections.select_anchor_ranges([target..target]);
 7393                    },
 7394                );
 7395            }
 7396            InlineCompletion::Edit { edits, .. } => {
 7397                // Find an insertion that starts at the cursor position.
 7398                let snapshot = self.buffer.read(cx).snapshot(cx);
 7399                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7400                let insertion = edits.iter().find_map(|(range, text)| {
 7401                    let range = range.to_offset(&snapshot);
 7402                    if range.is_empty() && range.start == cursor_offset {
 7403                        Some(text)
 7404                    } else {
 7405                        None
 7406                    }
 7407                });
 7408
 7409                if let Some(text) = insertion {
 7410                    let mut partial_completion = text
 7411                        .chars()
 7412                        .by_ref()
 7413                        .take_while(|c| c.is_alphabetic())
 7414                        .collect::<String>();
 7415                    if partial_completion.is_empty() {
 7416                        partial_completion = text
 7417                            .chars()
 7418                            .by_ref()
 7419                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7420                            .collect::<String>();
 7421                    }
 7422
 7423                    cx.emit(EditorEvent::InputHandled {
 7424                        utf16_range_to_replace: None,
 7425                        text: partial_completion.clone().into(),
 7426                    });
 7427
 7428                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7429
 7430                    self.refresh_inline_completion(true, true, window, cx);
 7431                    cx.notify();
 7432                } else {
 7433                    self.accept_edit_prediction(&Default::default(), window, cx);
 7434                }
 7435            }
 7436        }
 7437    }
 7438
 7439    fn discard_inline_completion(
 7440        &mut self,
 7441        should_report_inline_completion_event: bool,
 7442        cx: &mut Context<Self>,
 7443    ) -> bool {
 7444        if should_report_inline_completion_event {
 7445            let completion_id = self
 7446                .active_inline_completion
 7447                .as_ref()
 7448                .and_then(|active_completion| active_completion.completion_id.clone());
 7449
 7450            self.report_inline_completion_event(completion_id, false, cx);
 7451        }
 7452
 7453        if let Some(provider) = self.edit_prediction_provider() {
 7454            provider.discard(cx);
 7455        }
 7456
 7457        self.take_active_inline_completion(cx)
 7458    }
 7459
 7460    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7461        let Some(provider) = self.edit_prediction_provider() else {
 7462            return;
 7463        };
 7464
 7465        let Some((_, buffer, _)) = self
 7466            .buffer
 7467            .read(cx)
 7468            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7469        else {
 7470            return;
 7471        };
 7472
 7473        let extension = buffer
 7474            .read(cx)
 7475            .file()
 7476            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7477
 7478        let event_type = match accepted {
 7479            true => "Edit Prediction Accepted",
 7480            false => "Edit Prediction Discarded",
 7481        };
 7482        telemetry::event!(
 7483            event_type,
 7484            provider = provider.name(),
 7485            prediction_id = id,
 7486            suggestion_accepted = accepted,
 7487            file_extension = extension,
 7488        );
 7489    }
 7490
 7491    pub fn has_active_inline_completion(&self) -> bool {
 7492        self.active_inline_completion.is_some()
 7493    }
 7494
 7495    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7496        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7497            return false;
 7498        };
 7499
 7500        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7501        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7502        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7503        true
 7504    }
 7505
 7506    /// Returns true when we're displaying the edit prediction popover below the cursor
 7507    /// like we are not previewing and the LSP autocomplete menu is visible
 7508    /// or we are in `when_holding_modifier` mode.
 7509    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7510        if self.edit_prediction_preview_is_active()
 7511            || !self.show_edit_predictions_in_menu()
 7512            || !self.edit_predictions_enabled()
 7513        {
 7514            return false;
 7515        }
 7516
 7517        if self.has_visible_completions_menu() {
 7518            return true;
 7519        }
 7520
 7521        has_completion && self.edit_prediction_requires_modifier()
 7522    }
 7523
 7524    fn handle_modifiers_changed(
 7525        &mut self,
 7526        modifiers: Modifiers,
 7527        position_map: &PositionMap,
 7528        window: &mut Window,
 7529        cx: &mut Context<Self>,
 7530    ) {
 7531        if self.show_edit_predictions_in_menu() {
 7532            self.update_edit_prediction_preview(&modifiers, window, cx);
 7533        }
 7534
 7535        self.update_selection_mode(&modifiers, position_map, window, cx);
 7536
 7537        let mouse_position = window.mouse_position();
 7538        if !position_map.text_hitbox.is_hovered(window) {
 7539            return;
 7540        }
 7541
 7542        self.update_hovered_link(
 7543            position_map.point_for_position(mouse_position),
 7544            &position_map.snapshot,
 7545            modifiers,
 7546            window,
 7547            cx,
 7548        )
 7549    }
 7550
 7551    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7552        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7553        if invert {
 7554            match multi_cursor_setting {
 7555                MultiCursorModifier::Alt => modifiers.alt,
 7556                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7557            }
 7558        } else {
 7559            match multi_cursor_setting {
 7560                MultiCursorModifier::Alt => modifiers.secondary(),
 7561                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7562            }
 7563        }
 7564    }
 7565
 7566    fn columnar_selection_mode(
 7567        modifiers: &Modifiers,
 7568        cx: &mut Context<Self>,
 7569    ) -> Option<ColumnarMode> {
 7570        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7571            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7572                Some(ColumnarMode::FromMouse)
 7573            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7574                Some(ColumnarMode::FromSelection)
 7575            } else {
 7576                None
 7577            }
 7578        } else {
 7579            None
 7580        }
 7581    }
 7582
 7583    fn update_selection_mode(
 7584        &mut self,
 7585        modifiers: &Modifiers,
 7586        position_map: &PositionMap,
 7587        window: &mut Window,
 7588        cx: &mut Context<Self>,
 7589    ) {
 7590        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7591            return;
 7592        };
 7593        if self.selections.pending.is_none() {
 7594            return;
 7595        }
 7596
 7597        let mouse_position = window.mouse_position();
 7598        let point_for_position = position_map.point_for_position(mouse_position);
 7599        let position = point_for_position.previous_valid;
 7600
 7601        self.select(
 7602            SelectPhase::BeginColumnar {
 7603                position,
 7604                reset: false,
 7605                mode,
 7606                goal_column: point_for_position.exact_unclipped.column(),
 7607            },
 7608            window,
 7609            cx,
 7610        );
 7611    }
 7612
 7613    fn update_edit_prediction_preview(
 7614        &mut self,
 7615        modifiers: &Modifiers,
 7616        window: &mut Window,
 7617        cx: &mut Context<Self>,
 7618    ) {
 7619        let mut modifiers_held = false;
 7620        if let Some(accept_keystroke) = self
 7621            .accept_edit_prediction_keybind(false, window, cx)
 7622            .keystroke()
 7623        {
 7624            modifiers_held = modifiers_held
 7625                || (&accept_keystroke.modifiers == modifiers
 7626                    && accept_keystroke.modifiers.modified());
 7627        };
 7628        if let Some(accept_partial_keystroke) = self
 7629            .accept_edit_prediction_keybind(true, window, cx)
 7630            .keystroke()
 7631        {
 7632            modifiers_held = modifiers_held
 7633                || (&accept_partial_keystroke.modifiers == modifiers
 7634                    && accept_partial_keystroke.modifiers.modified());
 7635        }
 7636
 7637        if modifiers_held {
 7638            if matches!(
 7639                self.edit_prediction_preview,
 7640                EditPredictionPreview::Inactive { .. }
 7641            ) {
 7642                self.edit_prediction_preview = EditPredictionPreview::Active {
 7643                    previous_scroll_position: None,
 7644                    since: Instant::now(),
 7645                };
 7646
 7647                self.update_visible_inline_completion(window, cx);
 7648                cx.notify();
 7649            }
 7650        } else if let EditPredictionPreview::Active {
 7651            previous_scroll_position,
 7652            since,
 7653        } = self.edit_prediction_preview
 7654        {
 7655            if let (Some(previous_scroll_position), Some(position_map)) =
 7656                (previous_scroll_position, self.last_position_map.as_ref())
 7657            {
 7658                self.set_scroll_position(
 7659                    previous_scroll_position
 7660                        .scroll_position(&position_map.snapshot.display_snapshot),
 7661                    window,
 7662                    cx,
 7663                );
 7664            }
 7665
 7666            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7667                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7668            };
 7669            self.clear_row_highlights::<EditPredictionPreview>();
 7670            self.update_visible_inline_completion(window, cx);
 7671            cx.notify();
 7672        }
 7673    }
 7674
 7675    fn update_visible_inline_completion(
 7676        &mut self,
 7677        _window: &mut Window,
 7678        cx: &mut Context<Self>,
 7679    ) -> Option<()> {
 7680        let selection = self.selections.newest_anchor();
 7681        let cursor = selection.head();
 7682        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7683        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7684        let excerpt_id = cursor.excerpt_id;
 7685
 7686        let show_in_menu = self.show_edit_predictions_in_menu();
 7687        let completions_menu_has_precedence = !show_in_menu
 7688            && (self.context_menu.borrow().is_some()
 7689                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7690
 7691        if completions_menu_has_precedence
 7692            || !offset_selection.is_empty()
 7693            || self
 7694                .active_inline_completion
 7695                .as_ref()
 7696                .map_or(false, |completion| {
 7697                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7698                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7699                    !invalidation_range.contains(&offset_selection.head())
 7700                })
 7701        {
 7702            self.discard_inline_completion(false, cx);
 7703            return None;
 7704        }
 7705
 7706        self.take_active_inline_completion(cx);
 7707        let Some(provider) = self.edit_prediction_provider() else {
 7708            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7709            return None;
 7710        };
 7711
 7712        let (buffer, cursor_buffer_position) =
 7713            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7714
 7715        self.edit_prediction_settings =
 7716            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7717
 7718        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7719
 7720        if self.edit_prediction_indent_conflict {
 7721            let cursor_point = cursor.to_point(&multibuffer);
 7722
 7723            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7724
 7725            if let Some((_, indent)) = indents.iter().next() {
 7726                if indent.len == cursor_point.column {
 7727                    self.edit_prediction_indent_conflict = false;
 7728                }
 7729            }
 7730        }
 7731
 7732        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7733        let edits = inline_completion
 7734            .edits
 7735            .into_iter()
 7736            .flat_map(|(range, new_text)| {
 7737                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7738                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7739                Some((start..end, new_text))
 7740            })
 7741            .collect::<Vec<_>>();
 7742        if edits.is_empty() {
 7743            return None;
 7744        }
 7745
 7746        let first_edit_start = edits.first().unwrap().0.start;
 7747        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7748        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7749
 7750        let last_edit_end = edits.last().unwrap().0.end;
 7751        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7752        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7753
 7754        let cursor_row = cursor.to_point(&multibuffer).row;
 7755
 7756        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7757
 7758        let mut inlay_ids = Vec::new();
 7759        let invalidation_row_range;
 7760        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7761            Some(cursor_row..edit_end_row)
 7762        } else if cursor_row > edit_end_row {
 7763            Some(edit_start_row..cursor_row)
 7764        } else {
 7765            None
 7766        };
 7767        let is_move =
 7768            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7769        let completion = if is_move {
 7770            invalidation_row_range =
 7771                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7772            let target = first_edit_start;
 7773            InlineCompletion::Move { target, snapshot }
 7774        } else {
 7775            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7776                && !self.inline_completions_hidden_for_vim_mode;
 7777
 7778            if show_completions_in_buffer {
 7779                if edits
 7780                    .iter()
 7781                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7782                {
 7783                    let mut inlays = Vec::new();
 7784                    for (range, new_text) in &edits {
 7785                        let inlay = Inlay::inline_completion(
 7786                            post_inc(&mut self.next_inlay_id),
 7787                            range.start,
 7788                            new_text.as_str(),
 7789                        );
 7790                        inlay_ids.push(inlay.id);
 7791                        inlays.push(inlay);
 7792                    }
 7793
 7794                    self.splice_inlays(&[], inlays, cx);
 7795                } else {
 7796                    let background_color = cx.theme().status().deleted_background;
 7797                    self.highlight_text::<InlineCompletionHighlight>(
 7798                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7799                        HighlightStyle {
 7800                            background_color: Some(background_color),
 7801                            ..Default::default()
 7802                        },
 7803                        cx,
 7804                    );
 7805                }
 7806            }
 7807
 7808            invalidation_row_range = edit_start_row..edit_end_row;
 7809
 7810            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7811                if provider.show_tab_accept_marker() {
 7812                    EditDisplayMode::TabAccept
 7813                } else {
 7814                    EditDisplayMode::Inline
 7815                }
 7816            } else {
 7817                EditDisplayMode::DiffPopover
 7818            };
 7819
 7820            InlineCompletion::Edit {
 7821                edits,
 7822                edit_preview: inline_completion.edit_preview,
 7823                display_mode,
 7824                snapshot,
 7825            }
 7826        };
 7827
 7828        let invalidation_range = multibuffer
 7829            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7830            ..multibuffer.anchor_after(Point::new(
 7831                invalidation_row_range.end,
 7832                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7833            ));
 7834
 7835        self.stale_inline_completion_in_menu = None;
 7836        self.active_inline_completion = Some(InlineCompletionState {
 7837            inlay_ids,
 7838            completion,
 7839            completion_id: inline_completion.id,
 7840            invalidation_range,
 7841        });
 7842
 7843        cx.notify();
 7844
 7845        Some(())
 7846    }
 7847
 7848    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7849        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7850    }
 7851
 7852    fn clear_tasks(&mut self) {
 7853        self.tasks.clear()
 7854    }
 7855
 7856    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7857        if self.tasks.insert(key, value).is_some() {
 7858            // This case should hopefully be rare, but just in case...
 7859            log::error!(
 7860                "multiple different run targets found on a single line, only the last target will be rendered"
 7861            )
 7862        }
 7863    }
 7864
 7865    /// Get all display points of breakpoints that will be rendered within editor
 7866    ///
 7867    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7868    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7869    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7870    fn active_breakpoints(
 7871        &self,
 7872        range: Range<DisplayRow>,
 7873        window: &mut Window,
 7874        cx: &mut Context<Self>,
 7875    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7876        let mut breakpoint_display_points = HashMap::default();
 7877
 7878        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7879            return breakpoint_display_points;
 7880        };
 7881
 7882        let snapshot = self.snapshot(window, cx);
 7883
 7884        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7885        let Some(project) = self.project.as_ref() else {
 7886            return breakpoint_display_points;
 7887        };
 7888
 7889        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7890            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7891
 7892        for (buffer_snapshot, range, excerpt_id) in
 7893            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7894        {
 7895            let Some(buffer) = project
 7896                .read(cx)
 7897                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7898            else {
 7899                continue;
 7900            };
 7901            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7902                &buffer,
 7903                Some(
 7904                    buffer_snapshot.anchor_before(range.start)
 7905                        ..buffer_snapshot.anchor_after(range.end),
 7906                ),
 7907                buffer_snapshot,
 7908                cx,
 7909            );
 7910            for (breakpoint, state) in breakpoints {
 7911                let multi_buffer_anchor =
 7912                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7913                let position = multi_buffer_anchor
 7914                    .to_point(&multi_buffer_snapshot)
 7915                    .to_display_point(&snapshot);
 7916
 7917                breakpoint_display_points.insert(
 7918                    position.row(),
 7919                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7920                );
 7921            }
 7922        }
 7923
 7924        breakpoint_display_points
 7925    }
 7926
 7927    fn breakpoint_context_menu(
 7928        &self,
 7929        anchor: Anchor,
 7930        window: &mut Window,
 7931        cx: &mut Context<Self>,
 7932    ) -> Entity<ui::ContextMenu> {
 7933        let weak_editor = cx.weak_entity();
 7934        let focus_handle = self.focus_handle(cx);
 7935
 7936        let row = self
 7937            .buffer
 7938            .read(cx)
 7939            .snapshot(cx)
 7940            .summary_for_anchor::<Point>(&anchor)
 7941            .row;
 7942
 7943        let breakpoint = self
 7944            .breakpoint_at_row(row, window, cx)
 7945            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7946
 7947        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7948            "Edit Log Breakpoint"
 7949        } else {
 7950            "Set Log Breakpoint"
 7951        };
 7952
 7953        let condition_breakpoint_msg = if breakpoint
 7954            .as_ref()
 7955            .is_some_and(|bp| bp.1.condition.is_some())
 7956        {
 7957            "Edit Condition Breakpoint"
 7958        } else {
 7959            "Set Condition Breakpoint"
 7960        };
 7961
 7962        let hit_condition_breakpoint_msg = if breakpoint
 7963            .as_ref()
 7964            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7965        {
 7966            "Edit Hit Condition Breakpoint"
 7967        } else {
 7968            "Set Hit Condition Breakpoint"
 7969        };
 7970
 7971        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7972            "Unset Breakpoint"
 7973        } else {
 7974            "Set Breakpoint"
 7975        };
 7976
 7977        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7978
 7979        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7980            BreakpointState::Enabled => Some("Disable"),
 7981            BreakpointState::Disabled => Some("Enable"),
 7982        });
 7983
 7984        let (anchor, breakpoint) =
 7985            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7986
 7987        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7988            menu.on_blur_subscription(Subscription::new(|| {}))
 7989                .context(focus_handle)
 7990                .when(run_to_cursor, |this| {
 7991                    let weak_editor = weak_editor.clone();
 7992                    this.entry("Run to cursor", None, move |window, cx| {
 7993                        weak_editor
 7994                            .update(cx, |editor, cx| {
 7995                                editor.change_selections(
 7996                                    SelectionEffects::no_scroll(),
 7997                                    window,
 7998                                    cx,
 7999                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8000                                );
 8001                            })
 8002                            .ok();
 8003
 8004                        window.dispatch_action(Box::new(RunToCursor), cx);
 8005                    })
 8006                    .separator()
 8007                })
 8008                .when_some(toggle_state_msg, |this, msg| {
 8009                    this.entry(msg, None, {
 8010                        let weak_editor = weak_editor.clone();
 8011                        let breakpoint = breakpoint.clone();
 8012                        move |_window, cx| {
 8013                            weak_editor
 8014                                .update(cx, |this, cx| {
 8015                                    this.edit_breakpoint_at_anchor(
 8016                                        anchor,
 8017                                        breakpoint.as_ref().clone(),
 8018                                        BreakpointEditAction::InvertState,
 8019                                        cx,
 8020                                    );
 8021                                })
 8022                                .log_err();
 8023                        }
 8024                    })
 8025                })
 8026                .entry(set_breakpoint_msg, None, {
 8027                    let weak_editor = weak_editor.clone();
 8028                    let breakpoint = breakpoint.clone();
 8029                    move |_window, cx| {
 8030                        weak_editor
 8031                            .update(cx, |this, cx| {
 8032                                this.edit_breakpoint_at_anchor(
 8033                                    anchor,
 8034                                    breakpoint.as_ref().clone(),
 8035                                    BreakpointEditAction::Toggle,
 8036                                    cx,
 8037                                );
 8038                            })
 8039                            .log_err();
 8040                    }
 8041                })
 8042                .entry(log_breakpoint_msg, None, {
 8043                    let breakpoint = breakpoint.clone();
 8044                    let weak_editor = weak_editor.clone();
 8045                    move |window, cx| {
 8046                        weak_editor
 8047                            .update(cx, |this, cx| {
 8048                                this.add_edit_breakpoint_block(
 8049                                    anchor,
 8050                                    breakpoint.as_ref(),
 8051                                    BreakpointPromptEditAction::Log,
 8052                                    window,
 8053                                    cx,
 8054                                );
 8055                            })
 8056                            .log_err();
 8057                    }
 8058                })
 8059                .entry(condition_breakpoint_msg, None, {
 8060                    let breakpoint = breakpoint.clone();
 8061                    let weak_editor = weak_editor.clone();
 8062                    move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |this, cx| {
 8065                                this.add_edit_breakpoint_block(
 8066                                    anchor,
 8067                                    breakpoint.as_ref(),
 8068                                    BreakpointPromptEditAction::Condition,
 8069                                    window,
 8070                                    cx,
 8071                                );
 8072                            })
 8073                            .log_err();
 8074                    }
 8075                })
 8076                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8077                    weak_editor
 8078                        .update(cx, |this, cx| {
 8079                            this.add_edit_breakpoint_block(
 8080                                anchor,
 8081                                breakpoint.as_ref(),
 8082                                BreakpointPromptEditAction::HitCondition,
 8083                                window,
 8084                                cx,
 8085                            );
 8086                        })
 8087                        .log_err();
 8088                })
 8089        })
 8090    }
 8091
 8092    fn render_breakpoint(
 8093        &self,
 8094        position: Anchor,
 8095        row: DisplayRow,
 8096        breakpoint: &Breakpoint,
 8097        state: Option<BreakpointSessionState>,
 8098        cx: &mut Context<Self>,
 8099    ) -> IconButton {
 8100        let is_rejected = state.is_some_and(|s| !s.verified);
 8101        // Is it a breakpoint that shows up when hovering over gutter?
 8102        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8103            (false, false),
 8104            |PhantomBreakpointIndicator {
 8105                 is_active,
 8106                 display_row,
 8107                 collides_with_existing_breakpoint,
 8108             }| {
 8109                (
 8110                    is_active && display_row == row,
 8111                    collides_with_existing_breakpoint,
 8112                )
 8113            },
 8114        );
 8115
 8116        let (color, icon) = {
 8117            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8118                (false, false) => ui::IconName::DebugBreakpoint,
 8119                (true, false) => ui::IconName::DebugLogBreakpoint,
 8120                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8121                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8122            };
 8123
 8124            let color = if is_phantom {
 8125                Color::Hint
 8126            } else if is_rejected {
 8127                Color::Disabled
 8128            } else {
 8129                Color::Debugger
 8130            };
 8131
 8132            (color, icon)
 8133        };
 8134
 8135        let breakpoint = Arc::from(breakpoint.clone());
 8136
 8137        let alt_as_text = gpui::Keystroke {
 8138            modifiers: Modifiers::secondary_key(),
 8139            ..Default::default()
 8140        };
 8141        let primary_action_text = if breakpoint.is_disabled() {
 8142            "Enable breakpoint"
 8143        } else if is_phantom && !collides_with_existing {
 8144            "Set breakpoint"
 8145        } else {
 8146            "Unset breakpoint"
 8147        };
 8148        let focus_handle = self.focus_handle.clone();
 8149
 8150        let meta = if is_rejected {
 8151            SharedString::from("No executable code is associated with this line.")
 8152        } else if collides_with_existing && !breakpoint.is_disabled() {
 8153            SharedString::from(format!(
 8154                "{alt_as_text}-click to disable,\nright-click for more options."
 8155            ))
 8156        } else {
 8157            SharedString::from("Right-click for more options.")
 8158        };
 8159        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8160            .icon_size(IconSize::XSmall)
 8161            .size(ui::ButtonSize::None)
 8162            .when(is_rejected, |this| {
 8163                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8164            })
 8165            .icon_color(color)
 8166            .style(ButtonStyle::Transparent)
 8167            .on_click(cx.listener({
 8168                let breakpoint = breakpoint.clone();
 8169
 8170                move |editor, event: &ClickEvent, window, cx| {
 8171                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8172                        BreakpointEditAction::InvertState
 8173                    } else {
 8174                        BreakpointEditAction::Toggle
 8175                    };
 8176
 8177                    window.focus(&editor.focus_handle(cx));
 8178                    editor.edit_breakpoint_at_anchor(
 8179                        position,
 8180                        breakpoint.as_ref().clone(),
 8181                        edit_action,
 8182                        cx,
 8183                    );
 8184                }
 8185            }))
 8186            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8187                editor.set_breakpoint_context_menu(
 8188                    row,
 8189                    Some(position),
 8190                    event.down.position,
 8191                    window,
 8192                    cx,
 8193                );
 8194            }))
 8195            .tooltip(move |window, cx| {
 8196                Tooltip::with_meta_in(
 8197                    primary_action_text,
 8198                    Some(&ToggleBreakpoint),
 8199                    meta.clone(),
 8200                    &focus_handle,
 8201                    window,
 8202                    cx,
 8203                )
 8204            })
 8205    }
 8206
 8207    fn build_tasks_context(
 8208        project: &Entity<Project>,
 8209        buffer: &Entity<Buffer>,
 8210        buffer_row: u32,
 8211        tasks: &Arc<RunnableTasks>,
 8212        cx: &mut Context<Self>,
 8213    ) -> Task<Option<task::TaskContext>> {
 8214        let position = Point::new(buffer_row, tasks.column);
 8215        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8216        let location = Location {
 8217            buffer: buffer.clone(),
 8218            range: range_start..range_start,
 8219        };
 8220        // Fill in the environmental variables from the tree-sitter captures
 8221        let mut captured_task_variables = TaskVariables::default();
 8222        for (capture_name, value) in tasks.extra_variables.clone() {
 8223            captured_task_variables.insert(
 8224                task::VariableName::Custom(capture_name.into()),
 8225                value.clone(),
 8226            );
 8227        }
 8228        project.update(cx, |project, cx| {
 8229            project.task_store().update(cx, |task_store, cx| {
 8230                task_store.task_context_for_location(captured_task_variables, location, cx)
 8231            })
 8232        })
 8233    }
 8234
 8235    pub fn spawn_nearest_task(
 8236        &mut self,
 8237        action: &SpawnNearestTask,
 8238        window: &mut Window,
 8239        cx: &mut Context<Self>,
 8240    ) {
 8241        let Some((workspace, _)) = self.workspace.clone() else {
 8242            return;
 8243        };
 8244        let Some(project) = self.project.clone() else {
 8245            return;
 8246        };
 8247
 8248        // Try to find a closest, enclosing node using tree-sitter that has a task
 8249        let Some((buffer, buffer_row, tasks)) = self
 8250            .find_enclosing_node_task(cx)
 8251            // Or find the task that's closest in row-distance.
 8252            .or_else(|| self.find_closest_task(cx))
 8253        else {
 8254            return;
 8255        };
 8256
 8257        let reveal_strategy = action.reveal;
 8258        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8259        cx.spawn_in(window, async move |_, cx| {
 8260            let context = task_context.await?;
 8261            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8262
 8263            let resolved = &mut resolved_task.resolved;
 8264            resolved.reveal = reveal_strategy;
 8265
 8266            workspace
 8267                .update_in(cx, |workspace, window, cx| {
 8268                    workspace.schedule_resolved_task(
 8269                        task_source_kind,
 8270                        resolved_task,
 8271                        false,
 8272                        window,
 8273                        cx,
 8274                    );
 8275                })
 8276                .ok()
 8277        })
 8278        .detach();
 8279    }
 8280
 8281    fn find_closest_task(
 8282        &mut self,
 8283        cx: &mut Context<Self>,
 8284    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8285        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8286
 8287        let ((buffer_id, row), tasks) = self
 8288            .tasks
 8289            .iter()
 8290            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8291
 8292        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8293        let tasks = Arc::new(tasks.to_owned());
 8294        Some((buffer, *row, tasks))
 8295    }
 8296
 8297    fn find_enclosing_node_task(
 8298        &mut self,
 8299        cx: &mut Context<Self>,
 8300    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8301        let snapshot = self.buffer.read(cx).snapshot(cx);
 8302        let offset = self.selections.newest::<usize>(cx).head();
 8303        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8304        let buffer_id = excerpt.buffer().remote_id();
 8305
 8306        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8307        let mut cursor = layer.node().walk();
 8308
 8309        while cursor.goto_first_child_for_byte(offset).is_some() {
 8310            if cursor.node().end_byte() == offset {
 8311                cursor.goto_next_sibling();
 8312            }
 8313        }
 8314
 8315        // Ascend to the smallest ancestor that contains the range and has a task.
 8316        loop {
 8317            let node = cursor.node();
 8318            let node_range = node.byte_range();
 8319            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8320
 8321            // Check if this node contains our offset
 8322            if node_range.start <= offset && node_range.end >= offset {
 8323                // If it contains offset, check for task
 8324                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8325                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8326                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8327                }
 8328            }
 8329
 8330            if !cursor.goto_parent() {
 8331                break;
 8332            }
 8333        }
 8334        None
 8335    }
 8336
 8337    fn render_run_indicator(
 8338        &self,
 8339        _style: &EditorStyle,
 8340        is_active: bool,
 8341        row: DisplayRow,
 8342        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8343        cx: &mut Context<Self>,
 8344    ) -> IconButton {
 8345        let color = Color::Muted;
 8346        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8347
 8348        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8349            .shape(ui::IconButtonShape::Square)
 8350            .icon_size(IconSize::XSmall)
 8351            .icon_color(color)
 8352            .toggle_state(is_active)
 8353            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8354                let quick_launch = e.down.button == MouseButton::Left;
 8355                window.focus(&editor.focus_handle(cx));
 8356                editor.toggle_code_actions(
 8357                    &ToggleCodeActions {
 8358                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8359                        quick_launch,
 8360                    },
 8361                    window,
 8362                    cx,
 8363                );
 8364            }))
 8365            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8366                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8367            }))
 8368    }
 8369
 8370    pub fn context_menu_visible(&self) -> bool {
 8371        !self.edit_prediction_preview_is_active()
 8372            && self
 8373                .context_menu
 8374                .borrow()
 8375                .as_ref()
 8376                .map_or(false, |menu| menu.visible())
 8377    }
 8378
 8379    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8380        self.context_menu
 8381            .borrow()
 8382            .as_ref()
 8383            .map(|menu| menu.origin())
 8384    }
 8385
 8386    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8387        self.context_menu_options = Some(options);
 8388    }
 8389
 8390    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8391    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8392
 8393    fn render_edit_prediction_popover(
 8394        &mut self,
 8395        text_bounds: &Bounds<Pixels>,
 8396        content_origin: gpui::Point<Pixels>,
 8397        right_margin: Pixels,
 8398        editor_snapshot: &EditorSnapshot,
 8399        visible_row_range: Range<DisplayRow>,
 8400        scroll_top: f32,
 8401        scroll_bottom: f32,
 8402        line_layouts: &[LineWithInvisibles],
 8403        line_height: Pixels,
 8404        scroll_pixel_position: gpui::Point<Pixels>,
 8405        newest_selection_head: Option<DisplayPoint>,
 8406        editor_width: Pixels,
 8407        style: &EditorStyle,
 8408        window: &mut Window,
 8409        cx: &mut App,
 8410    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8411        if self.mode().is_minimap() {
 8412            return None;
 8413        }
 8414        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8415
 8416        if self.edit_prediction_visible_in_cursor_popover(true) {
 8417            return None;
 8418        }
 8419
 8420        match &active_inline_completion.completion {
 8421            InlineCompletion::Move { target, .. } => {
 8422                let target_display_point = target.to_display_point(editor_snapshot);
 8423
 8424                if self.edit_prediction_requires_modifier() {
 8425                    if !self.edit_prediction_preview_is_active() {
 8426                        return None;
 8427                    }
 8428
 8429                    self.render_edit_prediction_modifier_jump_popover(
 8430                        text_bounds,
 8431                        content_origin,
 8432                        visible_row_range,
 8433                        line_layouts,
 8434                        line_height,
 8435                        scroll_pixel_position,
 8436                        newest_selection_head,
 8437                        target_display_point,
 8438                        window,
 8439                        cx,
 8440                    )
 8441                } else {
 8442                    self.render_edit_prediction_eager_jump_popover(
 8443                        text_bounds,
 8444                        content_origin,
 8445                        editor_snapshot,
 8446                        visible_row_range,
 8447                        scroll_top,
 8448                        scroll_bottom,
 8449                        line_height,
 8450                        scroll_pixel_position,
 8451                        target_display_point,
 8452                        editor_width,
 8453                        window,
 8454                        cx,
 8455                    )
 8456                }
 8457            }
 8458            InlineCompletion::Edit {
 8459                display_mode: EditDisplayMode::Inline,
 8460                ..
 8461            } => None,
 8462            InlineCompletion::Edit {
 8463                display_mode: EditDisplayMode::TabAccept,
 8464                edits,
 8465                ..
 8466            } => {
 8467                let range = &edits.first()?.0;
 8468                let target_display_point = range.end.to_display_point(editor_snapshot);
 8469
 8470                self.render_edit_prediction_end_of_line_popover(
 8471                    "Accept",
 8472                    editor_snapshot,
 8473                    visible_row_range,
 8474                    target_display_point,
 8475                    line_height,
 8476                    scroll_pixel_position,
 8477                    content_origin,
 8478                    editor_width,
 8479                    window,
 8480                    cx,
 8481                )
 8482            }
 8483            InlineCompletion::Edit {
 8484                edits,
 8485                edit_preview,
 8486                display_mode: EditDisplayMode::DiffPopover,
 8487                snapshot,
 8488            } => self.render_edit_prediction_diff_popover(
 8489                text_bounds,
 8490                content_origin,
 8491                right_margin,
 8492                editor_snapshot,
 8493                visible_row_range,
 8494                line_layouts,
 8495                line_height,
 8496                scroll_pixel_position,
 8497                newest_selection_head,
 8498                editor_width,
 8499                style,
 8500                edits,
 8501                edit_preview,
 8502                snapshot,
 8503                window,
 8504                cx,
 8505            ),
 8506        }
 8507    }
 8508
 8509    fn render_edit_prediction_modifier_jump_popover(
 8510        &mut self,
 8511        text_bounds: &Bounds<Pixels>,
 8512        content_origin: gpui::Point<Pixels>,
 8513        visible_row_range: Range<DisplayRow>,
 8514        line_layouts: &[LineWithInvisibles],
 8515        line_height: Pixels,
 8516        scroll_pixel_position: gpui::Point<Pixels>,
 8517        newest_selection_head: Option<DisplayPoint>,
 8518        target_display_point: DisplayPoint,
 8519        window: &mut Window,
 8520        cx: &mut App,
 8521    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8522        let scrolled_content_origin =
 8523            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8524
 8525        const SCROLL_PADDING_Y: Pixels = px(12.);
 8526
 8527        if target_display_point.row() < visible_row_range.start {
 8528            return self.render_edit_prediction_scroll_popover(
 8529                |_| SCROLL_PADDING_Y,
 8530                IconName::ArrowUp,
 8531                visible_row_range,
 8532                line_layouts,
 8533                newest_selection_head,
 8534                scrolled_content_origin,
 8535                window,
 8536                cx,
 8537            );
 8538        } else if target_display_point.row() >= visible_row_range.end {
 8539            return self.render_edit_prediction_scroll_popover(
 8540                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8541                IconName::ArrowDown,
 8542                visible_row_range,
 8543                line_layouts,
 8544                newest_selection_head,
 8545                scrolled_content_origin,
 8546                window,
 8547                cx,
 8548            );
 8549        }
 8550
 8551        const POLE_WIDTH: Pixels = px(2.);
 8552
 8553        let line_layout =
 8554            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8555        let target_column = target_display_point.column() as usize;
 8556
 8557        let target_x = line_layout.x_for_index(target_column);
 8558        let target_y =
 8559            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8560
 8561        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8562
 8563        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8564        border_color.l += 0.001;
 8565
 8566        let mut element = v_flex()
 8567            .items_end()
 8568            .when(flag_on_right, |el| el.items_start())
 8569            .child(if flag_on_right {
 8570                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8571                    .rounded_bl(px(0.))
 8572                    .rounded_tl(px(0.))
 8573                    .border_l_2()
 8574                    .border_color(border_color)
 8575            } else {
 8576                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8577                    .rounded_br(px(0.))
 8578                    .rounded_tr(px(0.))
 8579                    .border_r_2()
 8580                    .border_color(border_color)
 8581            })
 8582            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8583            .into_any();
 8584
 8585        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8586
 8587        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8588            - point(
 8589                if flag_on_right {
 8590                    POLE_WIDTH
 8591                } else {
 8592                    size.width - POLE_WIDTH
 8593                },
 8594                size.height - line_height,
 8595            );
 8596
 8597        origin.x = origin.x.max(content_origin.x);
 8598
 8599        element.prepaint_at(origin, window, cx);
 8600
 8601        Some((element, origin))
 8602    }
 8603
 8604    fn render_edit_prediction_scroll_popover(
 8605        &mut self,
 8606        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8607        scroll_icon: IconName,
 8608        visible_row_range: Range<DisplayRow>,
 8609        line_layouts: &[LineWithInvisibles],
 8610        newest_selection_head: Option<DisplayPoint>,
 8611        scrolled_content_origin: gpui::Point<Pixels>,
 8612        window: &mut Window,
 8613        cx: &mut App,
 8614    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8615        let mut element = self
 8616            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8617            .into_any();
 8618
 8619        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8620
 8621        let cursor = newest_selection_head?;
 8622        let cursor_row_layout =
 8623            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8624        let cursor_column = cursor.column() as usize;
 8625
 8626        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8627
 8628        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8629
 8630        element.prepaint_at(origin, window, cx);
 8631        Some((element, origin))
 8632    }
 8633
 8634    fn render_edit_prediction_eager_jump_popover(
 8635        &mut self,
 8636        text_bounds: &Bounds<Pixels>,
 8637        content_origin: gpui::Point<Pixels>,
 8638        editor_snapshot: &EditorSnapshot,
 8639        visible_row_range: Range<DisplayRow>,
 8640        scroll_top: f32,
 8641        scroll_bottom: f32,
 8642        line_height: Pixels,
 8643        scroll_pixel_position: gpui::Point<Pixels>,
 8644        target_display_point: DisplayPoint,
 8645        editor_width: Pixels,
 8646        window: &mut Window,
 8647        cx: &mut App,
 8648    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8649        if target_display_point.row().as_f32() < scroll_top {
 8650            let mut element = self
 8651                .render_edit_prediction_line_popover(
 8652                    "Jump to Edit",
 8653                    Some(IconName::ArrowUp),
 8654                    window,
 8655                    cx,
 8656                )?
 8657                .into_any();
 8658
 8659            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8660            let offset = point(
 8661                (text_bounds.size.width - size.width) / 2.,
 8662                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8663            );
 8664
 8665            let origin = text_bounds.origin + offset;
 8666            element.prepaint_at(origin, window, cx);
 8667            Some((element, origin))
 8668        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8669            let mut element = self
 8670                .render_edit_prediction_line_popover(
 8671                    "Jump to Edit",
 8672                    Some(IconName::ArrowDown),
 8673                    window,
 8674                    cx,
 8675                )?
 8676                .into_any();
 8677
 8678            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8679            let offset = point(
 8680                (text_bounds.size.width - size.width) / 2.,
 8681                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8682            );
 8683
 8684            let origin = text_bounds.origin + offset;
 8685            element.prepaint_at(origin, window, cx);
 8686            Some((element, origin))
 8687        } else {
 8688            self.render_edit_prediction_end_of_line_popover(
 8689                "Jump to Edit",
 8690                editor_snapshot,
 8691                visible_row_range,
 8692                target_display_point,
 8693                line_height,
 8694                scroll_pixel_position,
 8695                content_origin,
 8696                editor_width,
 8697                window,
 8698                cx,
 8699            )
 8700        }
 8701    }
 8702
 8703    fn render_edit_prediction_end_of_line_popover(
 8704        self: &mut Editor,
 8705        label: &'static str,
 8706        editor_snapshot: &EditorSnapshot,
 8707        visible_row_range: Range<DisplayRow>,
 8708        target_display_point: DisplayPoint,
 8709        line_height: Pixels,
 8710        scroll_pixel_position: gpui::Point<Pixels>,
 8711        content_origin: gpui::Point<Pixels>,
 8712        editor_width: Pixels,
 8713        window: &mut Window,
 8714        cx: &mut App,
 8715    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8716        let target_line_end = DisplayPoint::new(
 8717            target_display_point.row(),
 8718            editor_snapshot.line_len(target_display_point.row()),
 8719        );
 8720
 8721        let mut element = self
 8722            .render_edit_prediction_line_popover(label, None, window, cx)?
 8723            .into_any();
 8724
 8725        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8726
 8727        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8728
 8729        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8730        let mut origin = start_point
 8731            + line_origin
 8732            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8733        origin.x = origin.x.max(content_origin.x);
 8734
 8735        let max_x = content_origin.x + editor_width - size.width;
 8736
 8737        if origin.x > max_x {
 8738            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8739
 8740            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8741                origin.y += offset;
 8742                IconName::ArrowUp
 8743            } else {
 8744                origin.y -= offset;
 8745                IconName::ArrowDown
 8746            };
 8747
 8748            element = self
 8749                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8750                .into_any();
 8751
 8752            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8753
 8754            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8755        }
 8756
 8757        element.prepaint_at(origin, window, cx);
 8758        Some((element, origin))
 8759    }
 8760
 8761    fn render_edit_prediction_diff_popover(
 8762        self: &Editor,
 8763        text_bounds: &Bounds<Pixels>,
 8764        content_origin: gpui::Point<Pixels>,
 8765        right_margin: Pixels,
 8766        editor_snapshot: &EditorSnapshot,
 8767        visible_row_range: Range<DisplayRow>,
 8768        line_layouts: &[LineWithInvisibles],
 8769        line_height: Pixels,
 8770        scroll_pixel_position: gpui::Point<Pixels>,
 8771        newest_selection_head: Option<DisplayPoint>,
 8772        editor_width: Pixels,
 8773        style: &EditorStyle,
 8774        edits: &Vec<(Range<Anchor>, String)>,
 8775        edit_preview: &Option<language::EditPreview>,
 8776        snapshot: &language::BufferSnapshot,
 8777        window: &mut Window,
 8778        cx: &mut App,
 8779    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8780        let edit_start = edits
 8781            .first()
 8782            .unwrap()
 8783            .0
 8784            .start
 8785            .to_display_point(editor_snapshot);
 8786        let edit_end = edits
 8787            .last()
 8788            .unwrap()
 8789            .0
 8790            .end
 8791            .to_display_point(editor_snapshot);
 8792
 8793        let is_visible = visible_row_range.contains(&edit_start.row())
 8794            || visible_row_range.contains(&edit_end.row());
 8795        if !is_visible {
 8796            return None;
 8797        }
 8798
 8799        let highlighted_edits =
 8800            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8801
 8802        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8803        let line_count = highlighted_edits.text.lines().count();
 8804
 8805        const BORDER_WIDTH: Pixels = px(1.);
 8806
 8807        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8808        let has_keybind = keybind.is_some();
 8809
 8810        let mut element = h_flex()
 8811            .items_start()
 8812            .child(
 8813                h_flex()
 8814                    .bg(cx.theme().colors().editor_background)
 8815                    .border(BORDER_WIDTH)
 8816                    .shadow_xs()
 8817                    .border_color(cx.theme().colors().border)
 8818                    .rounded_l_lg()
 8819                    .when(line_count > 1, |el| el.rounded_br_lg())
 8820                    .pr_1()
 8821                    .child(styled_text),
 8822            )
 8823            .child(
 8824                h_flex()
 8825                    .h(line_height + BORDER_WIDTH * 2.)
 8826                    .px_1p5()
 8827                    .gap_1()
 8828                    // Workaround: For some reason, there's a gap if we don't do this
 8829                    .ml(-BORDER_WIDTH)
 8830                    .shadow(vec![gpui::BoxShadow {
 8831                        color: gpui::black().opacity(0.05),
 8832                        offset: point(px(1.), px(1.)),
 8833                        blur_radius: px(2.),
 8834                        spread_radius: px(0.),
 8835                    }])
 8836                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8837                    .border(BORDER_WIDTH)
 8838                    .border_color(cx.theme().colors().border)
 8839                    .rounded_r_lg()
 8840                    .id("edit_prediction_diff_popover_keybind")
 8841                    .when(!has_keybind, |el| {
 8842                        let status_colors = cx.theme().status();
 8843
 8844                        el.bg(status_colors.error_background)
 8845                            .border_color(status_colors.error.opacity(0.6))
 8846                            .child(Icon::new(IconName::Info).color(Color::Error))
 8847                            .cursor_default()
 8848                            .hoverable_tooltip(move |_window, cx| {
 8849                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8850                            })
 8851                    })
 8852                    .children(keybind),
 8853            )
 8854            .into_any();
 8855
 8856        let longest_row =
 8857            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8858        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8859            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8860        } else {
 8861            layout_line(
 8862                longest_row,
 8863                editor_snapshot,
 8864                style,
 8865                editor_width,
 8866                |_| false,
 8867                window,
 8868                cx,
 8869            )
 8870            .width
 8871        };
 8872
 8873        let viewport_bounds =
 8874            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8875                right: -right_margin,
 8876                ..Default::default()
 8877            });
 8878
 8879        let x_after_longest =
 8880            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8881                - scroll_pixel_position.x;
 8882
 8883        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8884
 8885        // Fully visible if it can be displayed within the window (allow overlapping other
 8886        // panes). However, this is only allowed if the popover starts within text_bounds.
 8887        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8888            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8889
 8890        let mut origin = if can_position_to_the_right {
 8891            point(
 8892                x_after_longest,
 8893                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8894                    - scroll_pixel_position.y,
 8895            )
 8896        } else {
 8897            let cursor_row = newest_selection_head.map(|head| head.row());
 8898            let above_edit = edit_start
 8899                .row()
 8900                .0
 8901                .checked_sub(line_count as u32)
 8902                .map(DisplayRow);
 8903            let below_edit = Some(edit_end.row() + 1);
 8904            let above_cursor =
 8905                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8906            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8907
 8908            // Place the edit popover adjacent to the edit if there is a location
 8909            // available that is onscreen and does not obscure the cursor. Otherwise,
 8910            // place it adjacent to the cursor.
 8911            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8912                .into_iter()
 8913                .flatten()
 8914                .find(|&start_row| {
 8915                    let end_row = start_row + line_count as u32;
 8916                    visible_row_range.contains(&start_row)
 8917                        && visible_row_range.contains(&end_row)
 8918                        && cursor_row.map_or(true, |cursor_row| {
 8919                            !((start_row..end_row).contains(&cursor_row))
 8920                        })
 8921                })?;
 8922
 8923            content_origin
 8924                + point(
 8925                    -scroll_pixel_position.x,
 8926                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8927                )
 8928        };
 8929
 8930        origin.x -= BORDER_WIDTH;
 8931
 8932        window.defer_draw(element, origin, 1);
 8933
 8934        // Do not return an element, since it will already be drawn due to defer_draw.
 8935        None
 8936    }
 8937
 8938    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8939        px(30.)
 8940    }
 8941
 8942    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8943        if self.read_only(cx) {
 8944            cx.theme().players().read_only()
 8945        } else {
 8946            self.style.as_ref().unwrap().local_player
 8947        }
 8948    }
 8949
 8950    fn render_edit_prediction_accept_keybind(
 8951        &self,
 8952        window: &mut Window,
 8953        cx: &App,
 8954    ) -> Option<AnyElement> {
 8955        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8956        let accept_keystroke = accept_binding.keystroke()?;
 8957
 8958        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8959
 8960        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8961            Color::Accent
 8962        } else {
 8963            Color::Muted
 8964        };
 8965
 8966        h_flex()
 8967            .px_0p5()
 8968            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8969            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8970            .text_size(TextSize::XSmall.rems(cx))
 8971            .child(h_flex().children(ui::render_modifiers(
 8972                &accept_keystroke.modifiers,
 8973                PlatformStyle::platform(),
 8974                Some(modifiers_color),
 8975                Some(IconSize::XSmall.rems().into()),
 8976                true,
 8977            )))
 8978            .when(is_platform_style_mac, |parent| {
 8979                parent.child(accept_keystroke.key.clone())
 8980            })
 8981            .when(!is_platform_style_mac, |parent| {
 8982                parent.child(
 8983                    Key::new(
 8984                        util::capitalize(&accept_keystroke.key),
 8985                        Some(Color::Default),
 8986                    )
 8987                    .size(Some(IconSize::XSmall.rems().into())),
 8988                )
 8989            })
 8990            .into_any()
 8991            .into()
 8992    }
 8993
 8994    fn render_edit_prediction_line_popover(
 8995        &self,
 8996        label: impl Into<SharedString>,
 8997        icon: Option<IconName>,
 8998        window: &mut Window,
 8999        cx: &App,
 9000    ) -> Option<Stateful<Div>> {
 9001        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9002
 9003        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9004        let has_keybind = keybind.is_some();
 9005
 9006        let result = h_flex()
 9007            .id("ep-line-popover")
 9008            .py_0p5()
 9009            .pl_1()
 9010            .pr(padding_right)
 9011            .gap_1()
 9012            .rounded_md()
 9013            .border_1()
 9014            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9015            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9016            .shadow_xs()
 9017            .when(!has_keybind, |el| {
 9018                let status_colors = cx.theme().status();
 9019
 9020                el.bg(status_colors.error_background)
 9021                    .border_color(status_colors.error.opacity(0.6))
 9022                    .pl_2()
 9023                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9024                    .cursor_default()
 9025                    .hoverable_tooltip(move |_window, cx| {
 9026                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9027                    })
 9028            })
 9029            .children(keybind)
 9030            .child(
 9031                Label::new(label)
 9032                    .size(LabelSize::Small)
 9033                    .when(!has_keybind, |el| {
 9034                        el.color(cx.theme().status().error.into()).strikethrough()
 9035                    }),
 9036            )
 9037            .when(!has_keybind, |el| {
 9038                el.child(
 9039                    h_flex().ml_1().child(
 9040                        Icon::new(IconName::Info)
 9041                            .size(IconSize::Small)
 9042                            .color(cx.theme().status().error.into()),
 9043                    ),
 9044                )
 9045            })
 9046            .when_some(icon, |element, icon| {
 9047                element.child(
 9048                    div()
 9049                        .mt(px(1.5))
 9050                        .child(Icon::new(icon).size(IconSize::Small)),
 9051                )
 9052            });
 9053
 9054        Some(result)
 9055    }
 9056
 9057    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9058        let accent_color = cx.theme().colors().text_accent;
 9059        let editor_bg_color = cx.theme().colors().editor_background;
 9060        editor_bg_color.blend(accent_color.opacity(0.1))
 9061    }
 9062
 9063    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9064        let accent_color = cx.theme().colors().text_accent;
 9065        let editor_bg_color = cx.theme().colors().editor_background;
 9066        editor_bg_color.blend(accent_color.opacity(0.6))
 9067    }
 9068
 9069    fn render_edit_prediction_cursor_popover(
 9070        &self,
 9071        min_width: Pixels,
 9072        max_width: Pixels,
 9073        cursor_point: Point,
 9074        style: &EditorStyle,
 9075        accept_keystroke: Option<&gpui::Keystroke>,
 9076        _window: &Window,
 9077        cx: &mut Context<Editor>,
 9078    ) -> Option<AnyElement> {
 9079        let provider = self.edit_prediction_provider.as_ref()?;
 9080
 9081        if provider.provider.needs_terms_acceptance(cx) {
 9082            return Some(
 9083                h_flex()
 9084                    .min_w(min_width)
 9085                    .flex_1()
 9086                    .px_2()
 9087                    .py_1()
 9088                    .gap_3()
 9089                    .elevation_2(cx)
 9090                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9091                    .id("accept-terms")
 9092                    .cursor_pointer()
 9093                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9094                    .on_click(cx.listener(|this, _event, window, cx| {
 9095                        cx.stop_propagation();
 9096                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9097                        window.dispatch_action(
 9098                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9099                            cx,
 9100                        );
 9101                    }))
 9102                    .child(
 9103                        h_flex()
 9104                            .flex_1()
 9105                            .gap_2()
 9106                            .child(Icon::new(IconName::ZedPredict))
 9107                            .child(Label::new("Accept Terms of Service"))
 9108                            .child(div().w_full())
 9109                            .child(
 9110                                Icon::new(IconName::ArrowUpRight)
 9111                                    .color(Color::Muted)
 9112                                    .size(IconSize::Small),
 9113                            )
 9114                            .into_any_element(),
 9115                    )
 9116                    .into_any(),
 9117            );
 9118        }
 9119
 9120        let is_refreshing = provider.provider.is_refreshing(cx);
 9121
 9122        fn pending_completion_container() -> Div {
 9123            h_flex()
 9124                .h_full()
 9125                .flex_1()
 9126                .gap_2()
 9127                .child(Icon::new(IconName::ZedPredict))
 9128        }
 9129
 9130        let completion = match &self.active_inline_completion {
 9131            Some(prediction) => {
 9132                if !self.has_visible_completions_menu() {
 9133                    const RADIUS: Pixels = px(6.);
 9134                    const BORDER_WIDTH: Pixels = px(1.);
 9135
 9136                    return Some(
 9137                        h_flex()
 9138                            .elevation_2(cx)
 9139                            .border(BORDER_WIDTH)
 9140                            .border_color(cx.theme().colors().border)
 9141                            .when(accept_keystroke.is_none(), |el| {
 9142                                el.border_color(cx.theme().status().error)
 9143                            })
 9144                            .rounded(RADIUS)
 9145                            .rounded_tl(px(0.))
 9146                            .overflow_hidden()
 9147                            .child(div().px_1p5().child(match &prediction.completion {
 9148                                InlineCompletion::Move { target, snapshot } => {
 9149                                    use text::ToPoint as _;
 9150                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9151                                    {
 9152                                        Icon::new(IconName::ZedPredictDown)
 9153                                    } else {
 9154                                        Icon::new(IconName::ZedPredictUp)
 9155                                    }
 9156                                }
 9157                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9158                            }))
 9159                            .child(
 9160                                h_flex()
 9161                                    .gap_1()
 9162                                    .py_1()
 9163                                    .px_2()
 9164                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9165                                    .border_l_1()
 9166                                    .border_color(cx.theme().colors().border)
 9167                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9168                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9169                                        el.child(
 9170                                            Label::new("Hold")
 9171                                                .size(LabelSize::Small)
 9172                                                .when(accept_keystroke.is_none(), |el| {
 9173                                                    el.strikethrough()
 9174                                                })
 9175                                                .line_height_style(LineHeightStyle::UiLabel),
 9176                                        )
 9177                                    })
 9178                                    .id("edit_prediction_cursor_popover_keybind")
 9179                                    .when(accept_keystroke.is_none(), |el| {
 9180                                        let status_colors = cx.theme().status();
 9181
 9182                                        el.bg(status_colors.error_background)
 9183                                            .border_color(status_colors.error.opacity(0.6))
 9184                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9185                                            .cursor_default()
 9186                                            .hoverable_tooltip(move |_window, cx| {
 9187                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9188                                                    .into()
 9189                                            })
 9190                                    })
 9191                                    .when_some(
 9192                                        accept_keystroke.as_ref(),
 9193                                        |el, accept_keystroke| {
 9194                                            el.child(h_flex().children(ui::render_modifiers(
 9195                                                &accept_keystroke.modifiers,
 9196                                                PlatformStyle::platform(),
 9197                                                Some(Color::Default),
 9198                                                Some(IconSize::XSmall.rems().into()),
 9199                                                false,
 9200                                            )))
 9201                                        },
 9202                                    ),
 9203                            )
 9204                            .into_any(),
 9205                    );
 9206                }
 9207
 9208                self.render_edit_prediction_cursor_popover_preview(
 9209                    prediction,
 9210                    cursor_point,
 9211                    style,
 9212                    cx,
 9213                )?
 9214            }
 9215
 9216            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9217                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9218                    stale_completion,
 9219                    cursor_point,
 9220                    style,
 9221                    cx,
 9222                )?,
 9223
 9224                None => {
 9225                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9226                }
 9227            },
 9228
 9229            None => pending_completion_container().child(Label::new("No Prediction")),
 9230        };
 9231
 9232        let completion = if is_refreshing {
 9233            completion
 9234                .with_animation(
 9235                    "loading-completion",
 9236                    Animation::new(Duration::from_secs(2))
 9237                        .repeat()
 9238                        .with_easing(pulsating_between(0.4, 0.8)),
 9239                    |label, delta| label.opacity(delta),
 9240                )
 9241                .into_any_element()
 9242        } else {
 9243            completion.into_any_element()
 9244        };
 9245
 9246        let has_completion = self.active_inline_completion.is_some();
 9247
 9248        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9249        Some(
 9250            h_flex()
 9251                .min_w(min_width)
 9252                .max_w(max_width)
 9253                .flex_1()
 9254                .elevation_2(cx)
 9255                .border_color(cx.theme().colors().border)
 9256                .child(
 9257                    div()
 9258                        .flex_1()
 9259                        .py_1()
 9260                        .px_2()
 9261                        .overflow_hidden()
 9262                        .child(completion),
 9263                )
 9264                .when_some(accept_keystroke, |el, accept_keystroke| {
 9265                    if !accept_keystroke.modifiers.modified() {
 9266                        return el;
 9267                    }
 9268
 9269                    el.child(
 9270                        h_flex()
 9271                            .h_full()
 9272                            .border_l_1()
 9273                            .rounded_r_lg()
 9274                            .border_color(cx.theme().colors().border)
 9275                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9276                            .gap_1()
 9277                            .py_1()
 9278                            .px_2()
 9279                            .child(
 9280                                h_flex()
 9281                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9282                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9283                                    .child(h_flex().children(ui::render_modifiers(
 9284                                        &accept_keystroke.modifiers,
 9285                                        PlatformStyle::platform(),
 9286                                        Some(if !has_completion {
 9287                                            Color::Muted
 9288                                        } else {
 9289                                            Color::Default
 9290                                        }),
 9291                                        None,
 9292                                        false,
 9293                                    ))),
 9294                            )
 9295                            .child(Label::new("Preview").into_any_element())
 9296                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9297                    )
 9298                })
 9299                .into_any(),
 9300        )
 9301    }
 9302
 9303    fn render_edit_prediction_cursor_popover_preview(
 9304        &self,
 9305        completion: &InlineCompletionState,
 9306        cursor_point: Point,
 9307        style: &EditorStyle,
 9308        cx: &mut Context<Editor>,
 9309    ) -> Option<Div> {
 9310        use text::ToPoint as _;
 9311
 9312        fn render_relative_row_jump(
 9313            prefix: impl Into<String>,
 9314            current_row: u32,
 9315            target_row: u32,
 9316        ) -> Div {
 9317            let (row_diff, arrow) = if target_row < current_row {
 9318                (current_row - target_row, IconName::ArrowUp)
 9319            } else {
 9320                (target_row - current_row, IconName::ArrowDown)
 9321            };
 9322
 9323            h_flex()
 9324                .child(
 9325                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9326                        .color(Color::Muted)
 9327                        .size(LabelSize::Small),
 9328                )
 9329                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9330        }
 9331
 9332        match &completion.completion {
 9333            InlineCompletion::Move {
 9334                target, snapshot, ..
 9335            } => Some(
 9336                h_flex()
 9337                    .px_2()
 9338                    .gap_2()
 9339                    .flex_1()
 9340                    .child(
 9341                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9342                            Icon::new(IconName::ZedPredictDown)
 9343                        } else {
 9344                            Icon::new(IconName::ZedPredictUp)
 9345                        },
 9346                    )
 9347                    .child(Label::new("Jump to Edit")),
 9348            ),
 9349
 9350            InlineCompletion::Edit {
 9351                edits,
 9352                edit_preview,
 9353                snapshot,
 9354                display_mode: _,
 9355            } => {
 9356                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9357
 9358                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9359                    &snapshot,
 9360                    &edits,
 9361                    edit_preview.as_ref()?,
 9362                    true,
 9363                    cx,
 9364                )
 9365                .first_line_preview();
 9366
 9367                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9368                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9369
 9370                let preview = h_flex()
 9371                    .gap_1()
 9372                    .min_w_16()
 9373                    .child(styled_text)
 9374                    .when(has_more_lines, |parent| parent.child(""));
 9375
 9376                let left = if first_edit_row != cursor_point.row {
 9377                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9378                        .into_any_element()
 9379                } else {
 9380                    Icon::new(IconName::ZedPredict).into_any_element()
 9381                };
 9382
 9383                Some(
 9384                    h_flex()
 9385                        .h_full()
 9386                        .flex_1()
 9387                        .gap_2()
 9388                        .pr_1()
 9389                        .overflow_x_hidden()
 9390                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9391                        .child(left)
 9392                        .child(preview),
 9393                )
 9394            }
 9395        }
 9396    }
 9397
 9398    pub fn render_context_menu(
 9399        &self,
 9400        style: &EditorStyle,
 9401        max_height_in_lines: u32,
 9402        window: &mut Window,
 9403        cx: &mut Context<Editor>,
 9404    ) -> Option<AnyElement> {
 9405        let menu = self.context_menu.borrow();
 9406        let menu = menu.as_ref()?;
 9407        if !menu.visible() {
 9408            return None;
 9409        };
 9410        Some(menu.render(style, max_height_in_lines, window, cx))
 9411    }
 9412
 9413    fn render_context_menu_aside(
 9414        &mut self,
 9415        max_size: Size<Pixels>,
 9416        window: &mut Window,
 9417        cx: &mut Context<Editor>,
 9418    ) -> Option<AnyElement> {
 9419        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9420            if menu.visible() {
 9421                menu.render_aside(max_size, window, cx)
 9422            } else {
 9423                None
 9424            }
 9425        })
 9426    }
 9427
 9428    fn hide_context_menu(
 9429        &mut self,
 9430        window: &mut Window,
 9431        cx: &mut Context<Self>,
 9432    ) -> Option<CodeContextMenu> {
 9433        cx.notify();
 9434        self.completion_tasks.clear();
 9435        let context_menu = self.context_menu.borrow_mut().take();
 9436        self.stale_inline_completion_in_menu.take();
 9437        self.update_visible_inline_completion(window, cx);
 9438        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9439            if let Some(completion_provider) = &self.completion_provider {
 9440                completion_provider.selection_changed(None, window, cx);
 9441            }
 9442        }
 9443        context_menu
 9444    }
 9445
 9446    fn show_snippet_choices(
 9447        &mut self,
 9448        choices: &Vec<String>,
 9449        selection: Range<Anchor>,
 9450        cx: &mut Context<Self>,
 9451    ) {
 9452        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9453            (Some(a), Some(b)) if a == b => a,
 9454            _ => {
 9455                log::error!("expected anchor range to have matching buffer IDs");
 9456                return;
 9457            }
 9458        };
 9459        let multi_buffer = self.buffer().read(cx);
 9460        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9461            return;
 9462        };
 9463
 9464        let id = post_inc(&mut self.next_completion_id);
 9465        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9466        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9467            CompletionsMenu::new_snippet_choices(
 9468                id,
 9469                true,
 9470                choices,
 9471                selection,
 9472                buffer,
 9473                snippet_sort_order,
 9474            ),
 9475        ));
 9476    }
 9477
 9478    pub fn insert_snippet(
 9479        &mut self,
 9480        insertion_ranges: &[Range<usize>],
 9481        snippet: Snippet,
 9482        window: &mut Window,
 9483        cx: &mut Context<Self>,
 9484    ) -> Result<()> {
 9485        struct Tabstop<T> {
 9486            is_end_tabstop: bool,
 9487            ranges: Vec<Range<T>>,
 9488            choices: Option<Vec<String>>,
 9489        }
 9490
 9491        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9492            let snippet_text: Arc<str> = snippet.text.clone().into();
 9493            let edits = insertion_ranges
 9494                .iter()
 9495                .cloned()
 9496                .map(|range| (range, snippet_text.clone()));
 9497            let autoindent_mode = AutoindentMode::Block {
 9498                original_indent_columns: Vec::new(),
 9499            };
 9500            buffer.edit(edits, Some(autoindent_mode), cx);
 9501
 9502            let snapshot = &*buffer.read(cx);
 9503            let snippet = &snippet;
 9504            snippet
 9505                .tabstops
 9506                .iter()
 9507                .map(|tabstop| {
 9508                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9509                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9510                    });
 9511                    let mut tabstop_ranges = tabstop
 9512                        .ranges
 9513                        .iter()
 9514                        .flat_map(|tabstop_range| {
 9515                            let mut delta = 0_isize;
 9516                            insertion_ranges.iter().map(move |insertion_range| {
 9517                                let insertion_start = insertion_range.start as isize + delta;
 9518                                delta +=
 9519                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9520
 9521                                let start = ((insertion_start + tabstop_range.start) as usize)
 9522                                    .min(snapshot.len());
 9523                                let end = ((insertion_start + tabstop_range.end) as usize)
 9524                                    .min(snapshot.len());
 9525                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9526                            })
 9527                        })
 9528                        .collect::<Vec<_>>();
 9529                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9530
 9531                    Tabstop {
 9532                        is_end_tabstop,
 9533                        ranges: tabstop_ranges,
 9534                        choices: tabstop.choices.clone(),
 9535                    }
 9536                })
 9537                .collect::<Vec<_>>()
 9538        });
 9539        if let Some(tabstop) = tabstops.first() {
 9540            self.change_selections(Default::default(), window, cx, |s| {
 9541                // Reverse order so that the first range is the newest created selection.
 9542                // Completions will use it and autoscroll will prioritize it.
 9543                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9544            });
 9545
 9546            if let Some(choices) = &tabstop.choices {
 9547                if let Some(selection) = tabstop.ranges.first() {
 9548                    self.show_snippet_choices(choices, selection.clone(), cx)
 9549                }
 9550            }
 9551
 9552            // If we're already at the last tabstop and it's at the end of the snippet,
 9553            // we're done, we don't need to keep the state around.
 9554            if !tabstop.is_end_tabstop {
 9555                let choices = tabstops
 9556                    .iter()
 9557                    .map(|tabstop| tabstop.choices.clone())
 9558                    .collect();
 9559
 9560                let ranges = tabstops
 9561                    .into_iter()
 9562                    .map(|tabstop| tabstop.ranges)
 9563                    .collect::<Vec<_>>();
 9564
 9565                self.snippet_stack.push(SnippetState {
 9566                    active_index: 0,
 9567                    ranges,
 9568                    choices,
 9569                });
 9570            }
 9571
 9572            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9573            if self.autoclose_regions.is_empty() {
 9574                let snapshot = self.buffer.read(cx).snapshot(cx);
 9575                let mut all_selections = self.selections.all::<Point>(cx);
 9576                for selection in &mut all_selections {
 9577                    let selection_head = selection.head();
 9578                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9579                        continue;
 9580                    };
 9581
 9582                    let mut bracket_pair = None;
 9583                    let max_lookup_length = scope
 9584                        .brackets()
 9585                        .map(|(pair, _)| {
 9586                            pair.start
 9587                                .as_str()
 9588                                .chars()
 9589                                .count()
 9590                                .max(pair.end.as_str().chars().count())
 9591                        })
 9592                        .max();
 9593                    if let Some(max_lookup_length) = max_lookup_length {
 9594                        let next_text = snapshot
 9595                            .chars_at(selection_head)
 9596                            .take(max_lookup_length)
 9597                            .collect::<String>();
 9598                        let prev_text = snapshot
 9599                            .reversed_chars_at(selection_head)
 9600                            .take(max_lookup_length)
 9601                            .collect::<String>();
 9602
 9603                        for (pair, enabled) in scope.brackets() {
 9604                            if enabled
 9605                                && pair.close
 9606                                && prev_text.starts_with(pair.start.as_str())
 9607                                && next_text.starts_with(pair.end.as_str())
 9608                            {
 9609                                bracket_pair = Some(pair.clone());
 9610                                break;
 9611                            }
 9612                        }
 9613                    }
 9614
 9615                    if let Some(pair) = bracket_pair {
 9616                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9617                        let autoclose_enabled =
 9618                            self.use_autoclose && snapshot_settings.use_autoclose;
 9619                        if autoclose_enabled {
 9620                            let start = snapshot.anchor_after(selection_head);
 9621                            let end = snapshot.anchor_after(selection_head);
 9622                            self.autoclose_regions.push(AutocloseRegion {
 9623                                selection_id: selection.id,
 9624                                range: start..end,
 9625                                pair,
 9626                            });
 9627                        }
 9628                    }
 9629                }
 9630            }
 9631        }
 9632        Ok(())
 9633    }
 9634
 9635    pub fn move_to_next_snippet_tabstop(
 9636        &mut self,
 9637        window: &mut Window,
 9638        cx: &mut Context<Self>,
 9639    ) -> bool {
 9640        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9641    }
 9642
 9643    pub fn move_to_prev_snippet_tabstop(
 9644        &mut self,
 9645        window: &mut Window,
 9646        cx: &mut Context<Self>,
 9647    ) -> bool {
 9648        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9649    }
 9650
 9651    pub fn move_to_snippet_tabstop(
 9652        &mut self,
 9653        bias: Bias,
 9654        window: &mut Window,
 9655        cx: &mut Context<Self>,
 9656    ) -> bool {
 9657        if let Some(mut snippet) = self.snippet_stack.pop() {
 9658            match bias {
 9659                Bias::Left => {
 9660                    if snippet.active_index > 0 {
 9661                        snippet.active_index -= 1;
 9662                    } else {
 9663                        self.snippet_stack.push(snippet);
 9664                        return false;
 9665                    }
 9666                }
 9667                Bias::Right => {
 9668                    if snippet.active_index + 1 < snippet.ranges.len() {
 9669                        snippet.active_index += 1;
 9670                    } else {
 9671                        self.snippet_stack.push(snippet);
 9672                        return false;
 9673                    }
 9674                }
 9675            }
 9676            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9677                self.change_selections(Default::default(), window, cx, |s| {
 9678                    // Reverse order so that the first range is the newest created selection.
 9679                    // Completions will use it and autoscroll will prioritize it.
 9680                    s.select_ranges(current_ranges.iter().rev().cloned())
 9681                });
 9682
 9683                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9684                    if let Some(selection) = current_ranges.first() {
 9685                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9686                    }
 9687                }
 9688
 9689                // If snippet state is not at the last tabstop, push it back on the stack
 9690                if snippet.active_index + 1 < snippet.ranges.len() {
 9691                    self.snippet_stack.push(snippet);
 9692                }
 9693                return true;
 9694            }
 9695        }
 9696
 9697        false
 9698    }
 9699
 9700    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9701        self.transact(window, cx, |this, window, cx| {
 9702            this.select_all(&SelectAll, window, cx);
 9703            this.insert("", window, cx);
 9704        });
 9705    }
 9706
 9707    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9709        self.transact(window, cx, |this, window, cx| {
 9710            this.select_autoclose_pair(window, cx);
 9711            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9712            if !this.linked_edit_ranges.is_empty() {
 9713                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9714                let snapshot = this.buffer.read(cx).snapshot(cx);
 9715
 9716                for selection in selections.iter() {
 9717                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9718                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9719                    if selection_start.buffer_id != selection_end.buffer_id {
 9720                        continue;
 9721                    }
 9722                    if let Some(ranges) =
 9723                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9724                    {
 9725                        for (buffer, entries) in ranges {
 9726                            linked_ranges.entry(buffer).or_default().extend(entries);
 9727                        }
 9728                    }
 9729                }
 9730            }
 9731
 9732            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9733            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9734            for selection in &mut selections {
 9735                if selection.is_empty() {
 9736                    let old_head = selection.head();
 9737                    let mut new_head =
 9738                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9739                            .to_point(&display_map);
 9740                    if let Some((buffer, line_buffer_range)) = display_map
 9741                        .buffer_snapshot
 9742                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9743                    {
 9744                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9745                        let indent_len = match indent_size.kind {
 9746                            IndentKind::Space => {
 9747                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9748                            }
 9749                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9750                        };
 9751                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9752                            let indent_len = indent_len.get();
 9753                            new_head = cmp::min(
 9754                                new_head,
 9755                                MultiBufferPoint::new(
 9756                                    old_head.row,
 9757                                    ((old_head.column - 1) / indent_len) * indent_len,
 9758                                ),
 9759                            );
 9760                        }
 9761                    }
 9762
 9763                    selection.set_head(new_head, SelectionGoal::None);
 9764                }
 9765            }
 9766
 9767            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9768            this.insert("", window, cx);
 9769            let empty_str: Arc<str> = Arc::from("");
 9770            for (buffer, edits) in linked_ranges {
 9771                let snapshot = buffer.read(cx).snapshot();
 9772                use text::ToPoint as TP;
 9773
 9774                let edits = edits
 9775                    .into_iter()
 9776                    .map(|range| {
 9777                        let end_point = TP::to_point(&range.end, &snapshot);
 9778                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9779
 9780                        if end_point == start_point {
 9781                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9782                                .saturating_sub(1);
 9783                            start_point =
 9784                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9785                        };
 9786
 9787                        (start_point..end_point, empty_str.clone())
 9788                    })
 9789                    .sorted_by_key(|(range, _)| range.start)
 9790                    .collect::<Vec<_>>();
 9791                buffer.update(cx, |this, cx| {
 9792                    this.edit(edits, None, cx);
 9793                })
 9794            }
 9795            this.refresh_inline_completion(true, false, window, cx);
 9796            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9797        });
 9798    }
 9799
 9800    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9802        self.transact(window, cx, |this, window, cx| {
 9803            this.change_selections(Default::default(), window, cx, |s| {
 9804                s.move_with(|map, selection| {
 9805                    if selection.is_empty() {
 9806                        let cursor = movement::right(map, selection.head());
 9807                        selection.end = cursor;
 9808                        selection.reversed = true;
 9809                        selection.goal = SelectionGoal::None;
 9810                    }
 9811                })
 9812            });
 9813            this.insert("", window, cx);
 9814            this.refresh_inline_completion(true, false, window, cx);
 9815        });
 9816    }
 9817
 9818    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9819        if self.mode.is_single_line() {
 9820            cx.propagate();
 9821            return;
 9822        }
 9823
 9824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9825        if self.move_to_prev_snippet_tabstop(window, cx) {
 9826            return;
 9827        }
 9828        self.outdent(&Outdent, window, cx);
 9829    }
 9830
 9831    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9832        if self.mode.is_single_line() {
 9833            cx.propagate();
 9834            return;
 9835        }
 9836
 9837        if self.move_to_next_snippet_tabstop(window, cx) {
 9838            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9839            return;
 9840        }
 9841        if self.read_only(cx) {
 9842            return;
 9843        }
 9844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9845        let mut selections = self.selections.all_adjusted(cx);
 9846        let buffer = self.buffer.read(cx);
 9847        let snapshot = buffer.snapshot(cx);
 9848        let rows_iter = selections.iter().map(|s| s.head().row);
 9849        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9850
 9851        let has_some_cursor_in_whitespace = selections
 9852            .iter()
 9853            .filter(|selection| selection.is_empty())
 9854            .any(|selection| {
 9855                let cursor = selection.head();
 9856                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9857                cursor.column < current_indent.len
 9858            });
 9859
 9860        let mut edits = Vec::new();
 9861        let mut prev_edited_row = 0;
 9862        let mut row_delta = 0;
 9863        for selection in &mut selections {
 9864            if selection.start.row != prev_edited_row {
 9865                row_delta = 0;
 9866            }
 9867            prev_edited_row = selection.end.row;
 9868
 9869            // If the selection is non-empty, then increase the indentation of the selected lines.
 9870            if !selection.is_empty() {
 9871                row_delta =
 9872                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9873                continue;
 9874            }
 9875
 9876            let cursor = selection.head();
 9877            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9878            if let Some(suggested_indent) =
 9879                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9880            {
 9881                // Don't do anything if already at suggested indent
 9882                // and there is any other cursor which is not
 9883                if has_some_cursor_in_whitespace
 9884                    && cursor.column == current_indent.len
 9885                    && current_indent.len == suggested_indent.len
 9886                {
 9887                    continue;
 9888                }
 9889
 9890                // Adjust line and move cursor to suggested indent
 9891                // if cursor is not at suggested indent
 9892                if cursor.column < suggested_indent.len
 9893                    && cursor.column <= current_indent.len
 9894                    && current_indent.len <= suggested_indent.len
 9895                {
 9896                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9897                    selection.end = selection.start;
 9898                    if row_delta == 0 {
 9899                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9900                            cursor.row,
 9901                            current_indent,
 9902                            suggested_indent,
 9903                        ));
 9904                        row_delta = suggested_indent.len - current_indent.len;
 9905                    }
 9906                    continue;
 9907                }
 9908
 9909                // If current indent is more than suggested indent
 9910                // only move cursor to current indent and skip indent
 9911                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9912                    selection.start = Point::new(cursor.row, current_indent.len);
 9913                    selection.end = selection.start;
 9914                    continue;
 9915                }
 9916            }
 9917
 9918            // Otherwise, insert a hard or soft tab.
 9919            let settings = buffer.language_settings_at(cursor, cx);
 9920            let tab_size = if settings.hard_tabs {
 9921                IndentSize::tab()
 9922            } else {
 9923                let tab_size = settings.tab_size.get();
 9924                let indent_remainder = snapshot
 9925                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9926                    .flat_map(str::chars)
 9927                    .fold(row_delta % tab_size, |counter: u32, c| {
 9928                        if c == '\t' {
 9929                            0
 9930                        } else {
 9931                            (counter + 1) % tab_size
 9932                        }
 9933                    });
 9934
 9935                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9936                IndentSize::spaces(chars_to_next_tab_stop)
 9937            };
 9938            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9939            selection.end = selection.start;
 9940            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9941            row_delta += tab_size.len;
 9942        }
 9943
 9944        self.transact(window, cx, |this, window, cx| {
 9945            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9946            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9947            this.refresh_inline_completion(true, false, window, cx);
 9948        });
 9949    }
 9950
 9951    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9952        if self.read_only(cx) {
 9953            return;
 9954        }
 9955        if self.mode.is_single_line() {
 9956            cx.propagate();
 9957            return;
 9958        }
 9959
 9960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961        let mut selections = self.selections.all::<Point>(cx);
 9962        let mut prev_edited_row = 0;
 9963        let mut row_delta = 0;
 9964        let mut edits = Vec::new();
 9965        let buffer = self.buffer.read(cx);
 9966        let snapshot = buffer.snapshot(cx);
 9967        for selection in &mut selections {
 9968            if selection.start.row != prev_edited_row {
 9969                row_delta = 0;
 9970            }
 9971            prev_edited_row = selection.end.row;
 9972
 9973            row_delta =
 9974                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9975        }
 9976
 9977        self.transact(window, cx, |this, window, cx| {
 9978            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9979            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9980        });
 9981    }
 9982
 9983    fn indent_selection(
 9984        buffer: &MultiBuffer,
 9985        snapshot: &MultiBufferSnapshot,
 9986        selection: &mut Selection<Point>,
 9987        edits: &mut Vec<(Range<Point>, String)>,
 9988        delta_for_start_row: u32,
 9989        cx: &App,
 9990    ) -> u32 {
 9991        let settings = buffer.language_settings_at(selection.start, cx);
 9992        let tab_size = settings.tab_size.get();
 9993        let indent_kind = if settings.hard_tabs {
 9994            IndentKind::Tab
 9995        } else {
 9996            IndentKind::Space
 9997        };
 9998        let mut start_row = selection.start.row;
 9999        let mut end_row = selection.end.row + 1;
10000
10001        // If a selection ends at the beginning of a line, don't indent
10002        // that last line.
10003        if selection.end.column == 0 && selection.end.row > selection.start.row {
10004            end_row -= 1;
10005        }
10006
10007        // Avoid re-indenting a row that has already been indented by a
10008        // previous selection, but still update this selection's column
10009        // to reflect that indentation.
10010        if delta_for_start_row > 0 {
10011            start_row += 1;
10012            selection.start.column += delta_for_start_row;
10013            if selection.end.row == selection.start.row {
10014                selection.end.column += delta_for_start_row;
10015            }
10016        }
10017
10018        let mut delta_for_end_row = 0;
10019        let has_multiple_rows = start_row + 1 != end_row;
10020        for row in start_row..end_row {
10021            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10022            let indent_delta = match (current_indent.kind, indent_kind) {
10023                (IndentKind::Space, IndentKind::Space) => {
10024                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10025                    IndentSize::spaces(columns_to_next_tab_stop)
10026                }
10027                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10028                (_, IndentKind::Tab) => IndentSize::tab(),
10029            };
10030
10031            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10032                0
10033            } else {
10034                selection.start.column
10035            };
10036            let row_start = Point::new(row, start);
10037            edits.push((
10038                row_start..row_start,
10039                indent_delta.chars().collect::<String>(),
10040            ));
10041
10042            // Update this selection's endpoints to reflect the indentation.
10043            if row == selection.start.row {
10044                selection.start.column += indent_delta.len;
10045            }
10046            if row == selection.end.row {
10047                selection.end.column += indent_delta.len;
10048                delta_for_end_row = indent_delta.len;
10049            }
10050        }
10051
10052        if selection.start.row == selection.end.row {
10053            delta_for_start_row + delta_for_end_row
10054        } else {
10055            delta_for_end_row
10056        }
10057    }
10058
10059    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10060        if self.read_only(cx) {
10061            return;
10062        }
10063        if self.mode.is_single_line() {
10064            cx.propagate();
10065            return;
10066        }
10067
10068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10070        let selections = self.selections.all::<Point>(cx);
10071        let mut deletion_ranges = Vec::new();
10072        let mut last_outdent = None;
10073        {
10074            let buffer = self.buffer.read(cx);
10075            let snapshot = buffer.snapshot(cx);
10076            for selection in &selections {
10077                let settings = buffer.language_settings_at(selection.start, cx);
10078                let tab_size = settings.tab_size.get();
10079                let mut rows = selection.spanned_rows(false, &display_map);
10080
10081                // Avoid re-outdenting a row that has already been outdented by a
10082                // previous selection.
10083                if let Some(last_row) = last_outdent {
10084                    if last_row == rows.start {
10085                        rows.start = rows.start.next_row();
10086                    }
10087                }
10088                let has_multiple_rows = rows.len() > 1;
10089                for row in rows.iter_rows() {
10090                    let indent_size = snapshot.indent_size_for_line(row);
10091                    if indent_size.len > 0 {
10092                        let deletion_len = match indent_size.kind {
10093                            IndentKind::Space => {
10094                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10095                                if columns_to_prev_tab_stop == 0 {
10096                                    tab_size
10097                                } else {
10098                                    columns_to_prev_tab_stop
10099                                }
10100                            }
10101                            IndentKind::Tab => 1,
10102                        };
10103                        let start = if has_multiple_rows
10104                            || deletion_len > selection.start.column
10105                            || indent_size.len < selection.start.column
10106                        {
10107                            0
10108                        } else {
10109                            selection.start.column - deletion_len
10110                        };
10111                        deletion_ranges.push(
10112                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10113                        );
10114                        last_outdent = Some(row);
10115                    }
10116                }
10117            }
10118        }
10119
10120        self.transact(window, cx, |this, window, cx| {
10121            this.buffer.update(cx, |buffer, cx| {
10122                let empty_str: Arc<str> = Arc::default();
10123                buffer.edit(
10124                    deletion_ranges
10125                        .into_iter()
10126                        .map(|range| (range, empty_str.clone())),
10127                    None,
10128                    cx,
10129                );
10130            });
10131            let selections = this.selections.all::<usize>(cx);
10132            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10133        });
10134    }
10135
10136    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10137        if self.read_only(cx) {
10138            return;
10139        }
10140        if self.mode.is_single_line() {
10141            cx.propagate();
10142            return;
10143        }
10144
10145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10146        let selections = self
10147            .selections
10148            .all::<usize>(cx)
10149            .into_iter()
10150            .map(|s| s.range());
10151
10152        self.transact(window, cx, |this, window, cx| {
10153            this.buffer.update(cx, |buffer, cx| {
10154                buffer.autoindent_ranges(selections, cx);
10155            });
10156            let selections = this.selections.all::<usize>(cx);
10157            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10158        });
10159    }
10160
10161    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10164        let selections = self.selections.all::<Point>(cx);
10165
10166        let mut new_cursors = Vec::new();
10167        let mut edit_ranges = Vec::new();
10168        let mut selections = selections.iter().peekable();
10169        while let Some(selection) = selections.next() {
10170            let mut rows = selection.spanned_rows(false, &display_map);
10171            let goal_display_column = selection.head().to_display_point(&display_map).column();
10172
10173            // Accumulate contiguous regions of rows that we want to delete.
10174            while let Some(next_selection) = selections.peek() {
10175                let next_rows = next_selection.spanned_rows(false, &display_map);
10176                if next_rows.start <= rows.end {
10177                    rows.end = next_rows.end;
10178                    selections.next().unwrap();
10179                } else {
10180                    break;
10181                }
10182            }
10183
10184            let buffer = &display_map.buffer_snapshot;
10185            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10186            let edit_end;
10187            let cursor_buffer_row;
10188            if buffer.max_point().row >= rows.end.0 {
10189                // If there's a line after the range, delete the \n from the end of the row range
10190                // and position the cursor on the next line.
10191                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10192                cursor_buffer_row = rows.end;
10193            } else {
10194                // If there isn't a line after the range, delete the \n from the line before the
10195                // start of the row range and position the cursor there.
10196                edit_start = edit_start.saturating_sub(1);
10197                edit_end = buffer.len();
10198                cursor_buffer_row = rows.start.previous_row();
10199            }
10200
10201            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10202            *cursor.column_mut() =
10203                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10204
10205            new_cursors.push((
10206                selection.id,
10207                buffer.anchor_after(cursor.to_point(&display_map)),
10208            ));
10209            edit_ranges.push(edit_start..edit_end);
10210        }
10211
10212        self.transact(window, cx, |this, window, cx| {
10213            let buffer = this.buffer.update(cx, |buffer, cx| {
10214                let empty_str: Arc<str> = Arc::default();
10215                buffer.edit(
10216                    edit_ranges
10217                        .into_iter()
10218                        .map(|range| (range, empty_str.clone())),
10219                    None,
10220                    cx,
10221                );
10222                buffer.snapshot(cx)
10223            });
10224            let new_selections = new_cursors
10225                .into_iter()
10226                .map(|(id, cursor)| {
10227                    let cursor = cursor.to_point(&buffer);
10228                    Selection {
10229                        id,
10230                        start: cursor,
10231                        end: cursor,
10232                        reversed: false,
10233                        goal: SelectionGoal::None,
10234                    }
10235                })
10236                .collect();
10237
10238            this.change_selections(Default::default(), window, cx, |s| {
10239                s.select(new_selections);
10240            });
10241        });
10242    }
10243
10244    pub fn join_lines_impl(
10245        &mut self,
10246        insert_whitespace: bool,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        if self.read_only(cx) {
10251            return;
10252        }
10253        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10254        for selection in self.selections.all::<Point>(cx) {
10255            let start = MultiBufferRow(selection.start.row);
10256            // Treat single line selections as if they include the next line. Otherwise this action
10257            // would do nothing for single line selections individual cursors.
10258            let end = if selection.start.row == selection.end.row {
10259                MultiBufferRow(selection.start.row + 1)
10260            } else {
10261                MultiBufferRow(selection.end.row)
10262            };
10263
10264            if let Some(last_row_range) = row_ranges.last_mut() {
10265                if start <= last_row_range.end {
10266                    last_row_range.end = end;
10267                    continue;
10268                }
10269            }
10270            row_ranges.push(start..end);
10271        }
10272
10273        let snapshot = self.buffer.read(cx).snapshot(cx);
10274        let mut cursor_positions = Vec::new();
10275        for row_range in &row_ranges {
10276            let anchor = snapshot.anchor_before(Point::new(
10277                row_range.end.previous_row().0,
10278                snapshot.line_len(row_range.end.previous_row()),
10279            ));
10280            cursor_positions.push(anchor..anchor);
10281        }
10282
10283        self.transact(window, cx, |this, window, cx| {
10284            for row_range in row_ranges.into_iter().rev() {
10285                for row in row_range.iter_rows().rev() {
10286                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10287                    let next_line_row = row.next_row();
10288                    let indent = snapshot.indent_size_for_line(next_line_row);
10289                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10290
10291                    let replace =
10292                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10293                            " "
10294                        } else {
10295                            ""
10296                        };
10297
10298                    this.buffer.update(cx, |buffer, cx| {
10299                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10300                    });
10301                }
10302            }
10303
10304            this.change_selections(Default::default(), window, cx, |s| {
10305                s.select_anchor_ranges(cursor_positions)
10306            });
10307        });
10308    }
10309
10310    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10312        self.join_lines_impl(true, window, cx);
10313    }
10314
10315    pub fn sort_lines_case_sensitive(
10316        &mut self,
10317        _: &SortLinesCaseSensitive,
10318        window: &mut Window,
10319        cx: &mut Context<Self>,
10320    ) {
10321        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10322    }
10323
10324    pub fn sort_lines_by_length(
10325        &mut self,
10326        _: &SortLinesByLength,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        self.manipulate_immutable_lines(window, cx, |lines| {
10331            lines.sort_by_key(|&line| line.chars().count())
10332        })
10333    }
10334
10335    pub fn sort_lines_case_insensitive(
10336        &mut self,
10337        _: &SortLinesCaseInsensitive,
10338        window: &mut Window,
10339        cx: &mut Context<Self>,
10340    ) {
10341        self.manipulate_immutable_lines(window, cx, |lines| {
10342            lines.sort_by_key(|line| line.to_lowercase())
10343        })
10344    }
10345
10346    pub fn unique_lines_case_insensitive(
10347        &mut self,
10348        _: &UniqueLinesCaseInsensitive,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        self.manipulate_immutable_lines(window, cx, |lines| {
10353            let mut seen = HashSet::default();
10354            lines.retain(|line| seen.insert(line.to_lowercase()));
10355        })
10356    }
10357
10358    pub fn unique_lines_case_sensitive(
10359        &mut self,
10360        _: &UniqueLinesCaseSensitive,
10361        window: &mut Window,
10362        cx: &mut Context<Self>,
10363    ) {
10364        self.manipulate_immutable_lines(window, cx, |lines| {
10365            let mut seen = HashSet::default();
10366            lines.retain(|line| seen.insert(*line));
10367        })
10368    }
10369
10370    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10371        let Some(project) = self.project.clone() else {
10372            return;
10373        };
10374        self.reload(project, window, cx)
10375            .detach_and_notify_err(window, cx);
10376    }
10377
10378    pub fn restore_file(
10379        &mut self,
10380        _: &::git::RestoreFile,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10385        let mut buffer_ids = HashSet::default();
10386        let snapshot = self.buffer().read(cx).snapshot(cx);
10387        for selection in self.selections.all::<usize>(cx) {
10388            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10389        }
10390
10391        let buffer = self.buffer().read(cx);
10392        let ranges = buffer_ids
10393            .into_iter()
10394            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10395            .collect::<Vec<_>>();
10396
10397        self.restore_hunks_in_ranges(ranges, window, cx);
10398    }
10399
10400    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10402        let selections = self
10403            .selections
10404            .all(cx)
10405            .into_iter()
10406            .map(|s| s.range())
10407            .collect();
10408        self.restore_hunks_in_ranges(selections, window, cx);
10409    }
10410
10411    pub fn restore_hunks_in_ranges(
10412        &mut self,
10413        ranges: Vec<Range<Point>>,
10414        window: &mut Window,
10415        cx: &mut Context<Editor>,
10416    ) {
10417        let mut revert_changes = HashMap::default();
10418        let chunk_by = self
10419            .snapshot(window, cx)
10420            .hunks_for_ranges(ranges)
10421            .into_iter()
10422            .chunk_by(|hunk| hunk.buffer_id);
10423        for (buffer_id, hunks) in &chunk_by {
10424            let hunks = hunks.collect::<Vec<_>>();
10425            for hunk in &hunks {
10426                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10427            }
10428            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10429        }
10430        drop(chunk_by);
10431        if !revert_changes.is_empty() {
10432            self.transact(window, cx, |editor, window, cx| {
10433                editor.restore(revert_changes, window, cx);
10434            });
10435        }
10436    }
10437
10438    pub fn open_active_item_in_terminal(
10439        &mut self,
10440        _: &OpenInTerminal,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10445            let project_path = buffer.read(cx).project_path(cx)?;
10446            let project = self.project.as_ref()?.read(cx);
10447            let entry = project.entry_for_path(&project_path, cx)?;
10448            let parent = match &entry.canonical_path {
10449                Some(canonical_path) => canonical_path.to_path_buf(),
10450                None => project.absolute_path(&project_path, cx)?,
10451            }
10452            .parent()?
10453            .to_path_buf();
10454            Some(parent)
10455        }) {
10456            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10457        }
10458    }
10459
10460    fn set_breakpoint_context_menu(
10461        &mut self,
10462        display_row: DisplayRow,
10463        position: Option<Anchor>,
10464        clicked_point: gpui::Point<Pixels>,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        let source = self
10469            .buffer
10470            .read(cx)
10471            .snapshot(cx)
10472            .anchor_before(Point::new(display_row.0, 0u32));
10473
10474        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10475
10476        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10477            self,
10478            source,
10479            clicked_point,
10480            context_menu,
10481            window,
10482            cx,
10483        );
10484    }
10485
10486    fn add_edit_breakpoint_block(
10487        &mut self,
10488        anchor: Anchor,
10489        breakpoint: &Breakpoint,
10490        edit_action: BreakpointPromptEditAction,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        let weak_editor = cx.weak_entity();
10495        let bp_prompt = cx.new(|cx| {
10496            BreakpointPromptEditor::new(
10497                weak_editor,
10498                anchor,
10499                breakpoint.clone(),
10500                edit_action,
10501                window,
10502                cx,
10503            )
10504        });
10505
10506        let height = bp_prompt.update(cx, |this, cx| {
10507            this.prompt
10508                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10509        });
10510        let cloned_prompt = bp_prompt.clone();
10511        let blocks = vec![BlockProperties {
10512            style: BlockStyle::Sticky,
10513            placement: BlockPlacement::Above(anchor),
10514            height: Some(height),
10515            render: Arc::new(move |cx| {
10516                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10517                cloned_prompt.clone().into_any_element()
10518            }),
10519            priority: 0,
10520        }];
10521
10522        let focus_handle = bp_prompt.focus_handle(cx);
10523        window.focus(&focus_handle);
10524
10525        let block_ids = self.insert_blocks(blocks, None, cx);
10526        bp_prompt.update(cx, |prompt, _| {
10527            prompt.add_block_ids(block_ids);
10528        });
10529    }
10530
10531    pub(crate) fn breakpoint_at_row(
10532        &self,
10533        row: u32,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) -> Option<(Anchor, Breakpoint)> {
10537        let snapshot = self.snapshot(window, cx);
10538        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10539
10540        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10541    }
10542
10543    pub(crate) fn breakpoint_at_anchor(
10544        &self,
10545        breakpoint_position: Anchor,
10546        snapshot: &EditorSnapshot,
10547        cx: &mut Context<Self>,
10548    ) -> Option<(Anchor, Breakpoint)> {
10549        let project = self.project.clone()?;
10550
10551        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10552            snapshot
10553                .buffer_snapshot
10554                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10555        })?;
10556
10557        let enclosing_excerpt = breakpoint_position.excerpt_id;
10558        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10559        let buffer_snapshot = buffer.read(cx).snapshot();
10560
10561        let row = buffer_snapshot
10562            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10563            .row;
10564
10565        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10566        let anchor_end = snapshot
10567            .buffer_snapshot
10568            .anchor_after(Point::new(row, line_len));
10569
10570        let bp = self
10571            .breakpoint_store
10572            .as_ref()?
10573            .read_with(cx, |breakpoint_store, cx| {
10574                breakpoint_store
10575                    .breakpoints(
10576                        &buffer,
10577                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10578                        &buffer_snapshot,
10579                        cx,
10580                    )
10581                    .next()
10582                    .and_then(|(bp, _)| {
10583                        let breakpoint_row = buffer_snapshot
10584                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10585                            .row;
10586
10587                        if breakpoint_row == row {
10588                            snapshot
10589                                .buffer_snapshot
10590                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10591                                .map(|position| (position, bp.bp.clone()))
10592                        } else {
10593                            None
10594                        }
10595                    })
10596            });
10597        bp
10598    }
10599
10600    pub fn edit_log_breakpoint(
10601        &mut self,
10602        _: &EditLogBreakpoint,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10607            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10608                message: None,
10609                state: BreakpointState::Enabled,
10610                condition: None,
10611                hit_condition: None,
10612            });
10613
10614            self.add_edit_breakpoint_block(
10615                anchor,
10616                &breakpoint,
10617                BreakpointPromptEditAction::Log,
10618                window,
10619                cx,
10620            );
10621        }
10622    }
10623
10624    fn breakpoints_at_cursors(
10625        &self,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10629        let snapshot = self.snapshot(window, cx);
10630        let cursors = self
10631            .selections
10632            .disjoint_anchors()
10633            .into_iter()
10634            .map(|selection| {
10635                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10636
10637                let breakpoint_position = self
10638                    .breakpoint_at_row(cursor_position.row, window, cx)
10639                    .map(|bp| bp.0)
10640                    .unwrap_or_else(|| {
10641                        snapshot
10642                            .display_snapshot
10643                            .buffer_snapshot
10644                            .anchor_after(Point::new(cursor_position.row, 0))
10645                    });
10646
10647                let breakpoint = self
10648                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10649                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10650
10651                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10652            })
10653            // 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.
10654            .collect::<HashMap<Anchor, _>>();
10655
10656        cursors.into_iter().collect()
10657    }
10658
10659    pub fn enable_breakpoint(
10660        &mut self,
10661        _: &crate::actions::EnableBreakpoint,
10662        window: &mut Window,
10663        cx: &mut Context<Self>,
10664    ) {
10665        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10666            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10667                continue;
10668            };
10669            self.edit_breakpoint_at_anchor(
10670                anchor,
10671                breakpoint,
10672                BreakpointEditAction::InvertState,
10673                cx,
10674            );
10675        }
10676    }
10677
10678    pub fn disable_breakpoint(
10679        &mut self,
10680        _: &crate::actions::DisableBreakpoint,
10681        window: &mut Window,
10682        cx: &mut Context<Self>,
10683    ) {
10684        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10685            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10686                continue;
10687            };
10688            self.edit_breakpoint_at_anchor(
10689                anchor,
10690                breakpoint,
10691                BreakpointEditAction::InvertState,
10692                cx,
10693            );
10694        }
10695    }
10696
10697    pub fn toggle_breakpoint(
10698        &mut self,
10699        _: &crate::actions::ToggleBreakpoint,
10700        window: &mut Window,
10701        cx: &mut Context<Self>,
10702    ) {
10703        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10704            if let Some(breakpoint) = breakpoint {
10705                self.edit_breakpoint_at_anchor(
10706                    anchor,
10707                    breakpoint,
10708                    BreakpointEditAction::Toggle,
10709                    cx,
10710                );
10711            } else {
10712                self.edit_breakpoint_at_anchor(
10713                    anchor,
10714                    Breakpoint::new_standard(),
10715                    BreakpointEditAction::Toggle,
10716                    cx,
10717                );
10718            }
10719        }
10720    }
10721
10722    pub fn edit_breakpoint_at_anchor(
10723        &mut self,
10724        breakpoint_position: Anchor,
10725        breakpoint: Breakpoint,
10726        edit_action: BreakpointEditAction,
10727        cx: &mut Context<Self>,
10728    ) {
10729        let Some(breakpoint_store) = &self.breakpoint_store else {
10730            return;
10731        };
10732
10733        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10734            if breakpoint_position == Anchor::min() {
10735                self.buffer()
10736                    .read(cx)
10737                    .excerpt_buffer_ids()
10738                    .into_iter()
10739                    .next()
10740            } else {
10741                None
10742            }
10743        }) else {
10744            return;
10745        };
10746
10747        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10748            return;
10749        };
10750
10751        breakpoint_store.update(cx, |breakpoint_store, cx| {
10752            breakpoint_store.toggle_breakpoint(
10753                buffer,
10754                BreakpointWithPosition {
10755                    position: breakpoint_position.text_anchor,
10756                    bp: breakpoint,
10757                },
10758                edit_action,
10759                cx,
10760            );
10761        });
10762
10763        cx.notify();
10764    }
10765
10766    #[cfg(any(test, feature = "test-support"))]
10767    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10768        self.breakpoint_store.clone()
10769    }
10770
10771    pub fn prepare_restore_change(
10772        &self,
10773        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10774        hunk: &MultiBufferDiffHunk,
10775        cx: &mut App,
10776    ) -> Option<()> {
10777        if hunk.is_created_file() {
10778            return None;
10779        }
10780        let buffer = self.buffer.read(cx);
10781        let diff = buffer.diff_for(hunk.buffer_id)?;
10782        let buffer = buffer.buffer(hunk.buffer_id)?;
10783        let buffer = buffer.read(cx);
10784        let original_text = diff
10785            .read(cx)
10786            .base_text()
10787            .as_rope()
10788            .slice(hunk.diff_base_byte_range.clone());
10789        let buffer_snapshot = buffer.snapshot();
10790        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10791        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10792            probe
10793                .0
10794                .start
10795                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10796                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10797        }) {
10798            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10799            Some(())
10800        } else {
10801            None
10802        }
10803    }
10804
10805    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10806        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10807    }
10808
10809    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10810        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10811    }
10812
10813    fn manipulate_lines<M>(
10814        &mut self,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817        mut manipulate: M,
10818    ) where
10819        M: FnMut(&str) -> LineManipulationResult,
10820    {
10821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10822
10823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10824        let buffer = self.buffer.read(cx).snapshot(cx);
10825
10826        let mut edits = Vec::new();
10827
10828        let selections = self.selections.all::<Point>(cx);
10829        let mut selections = selections.iter().peekable();
10830        let mut contiguous_row_selections = Vec::new();
10831        let mut new_selections = Vec::new();
10832        let mut added_lines = 0;
10833        let mut removed_lines = 0;
10834
10835        while let Some(selection) = selections.next() {
10836            let (start_row, end_row) = consume_contiguous_rows(
10837                &mut contiguous_row_selections,
10838                selection,
10839                &display_map,
10840                &mut selections,
10841            );
10842
10843            let start_point = Point::new(start_row.0, 0);
10844            let end_point = Point::new(
10845                end_row.previous_row().0,
10846                buffer.line_len(end_row.previous_row()),
10847            );
10848            let text = buffer
10849                .text_for_range(start_point..end_point)
10850                .collect::<String>();
10851
10852            let LineManipulationResult {
10853                new_text,
10854                line_count_before,
10855                line_count_after,
10856            } = manipulate(&text);
10857
10858            edits.push((start_point..end_point, new_text));
10859
10860            // Selections must change based on added and removed line count
10861            let start_row =
10862                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10863            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10864            new_selections.push(Selection {
10865                id: selection.id,
10866                start: start_row,
10867                end: end_row,
10868                goal: SelectionGoal::None,
10869                reversed: selection.reversed,
10870            });
10871
10872            if line_count_after > line_count_before {
10873                added_lines += line_count_after - line_count_before;
10874            } else if line_count_before > line_count_after {
10875                removed_lines += line_count_before - line_count_after;
10876            }
10877        }
10878
10879        self.transact(window, cx, |this, window, cx| {
10880            let buffer = this.buffer.update(cx, |buffer, cx| {
10881                buffer.edit(edits, None, cx);
10882                buffer.snapshot(cx)
10883            });
10884
10885            // Recalculate offsets on newly edited buffer
10886            let new_selections = new_selections
10887                .iter()
10888                .map(|s| {
10889                    let start_point = Point::new(s.start.0, 0);
10890                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10891                    Selection {
10892                        id: s.id,
10893                        start: buffer.point_to_offset(start_point),
10894                        end: buffer.point_to_offset(end_point),
10895                        goal: s.goal,
10896                        reversed: s.reversed,
10897                    }
10898                })
10899                .collect();
10900
10901            this.change_selections(Default::default(), window, cx, |s| {
10902                s.select(new_selections);
10903            });
10904
10905            this.request_autoscroll(Autoscroll::fit(), cx);
10906        });
10907    }
10908
10909    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10910        self.manipulate_text(window, cx, |text| {
10911            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10912            if has_upper_case_characters {
10913                text.to_lowercase()
10914            } else {
10915                text.to_uppercase()
10916            }
10917        })
10918    }
10919
10920    fn manipulate_immutable_lines<Fn>(
10921        &mut self,
10922        window: &mut Window,
10923        cx: &mut Context<Self>,
10924        mut callback: Fn,
10925    ) where
10926        Fn: FnMut(&mut Vec<&str>),
10927    {
10928        self.manipulate_lines(window, cx, |text| {
10929            let mut lines: Vec<&str> = text.split('\n').collect();
10930            let line_count_before = lines.len();
10931
10932            callback(&mut lines);
10933
10934            LineManipulationResult {
10935                new_text: lines.join("\n"),
10936                line_count_before,
10937                line_count_after: lines.len(),
10938            }
10939        });
10940    }
10941
10942    fn manipulate_mutable_lines<Fn>(
10943        &mut self,
10944        window: &mut Window,
10945        cx: &mut Context<Self>,
10946        mut callback: Fn,
10947    ) where
10948        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10949    {
10950        self.manipulate_lines(window, cx, |text| {
10951            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10952            let line_count_before = lines.len();
10953
10954            callback(&mut lines);
10955
10956            LineManipulationResult {
10957                new_text: lines.join("\n"),
10958                line_count_before,
10959                line_count_after: lines.len(),
10960            }
10961        });
10962    }
10963
10964    pub fn convert_indentation_to_spaces(
10965        &mut self,
10966        _: &ConvertIndentationToSpaces,
10967        window: &mut Window,
10968        cx: &mut Context<Self>,
10969    ) {
10970        let settings = self.buffer.read(cx).language_settings(cx);
10971        let tab_size = settings.tab_size.get() as usize;
10972
10973        self.manipulate_mutable_lines(window, cx, |lines| {
10974            // Allocates a reasonably sized scratch buffer once for the whole loop
10975            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10976            // Avoids recomputing spaces that could be inserted many times
10977            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10978                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10979                .collect();
10980
10981            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10982                let mut chars = line.as_ref().chars();
10983                let mut col = 0;
10984                let mut changed = false;
10985
10986                while let Some(ch) = chars.next() {
10987                    match ch {
10988                        ' ' => {
10989                            reindented_line.push(' ');
10990                            col += 1;
10991                        }
10992                        '\t' => {
10993                            // \t are converted to spaces depending on the current column
10994                            let spaces_len = tab_size - (col % tab_size);
10995                            reindented_line.extend(&space_cache[spaces_len - 1]);
10996                            col += spaces_len;
10997                            changed = true;
10998                        }
10999                        _ => {
11000                            // If we dont append before break, the character is consumed
11001                            reindented_line.push(ch);
11002                            break;
11003                        }
11004                    }
11005                }
11006
11007                if !changed {
11008                    reindented_line.clear();
11009                    continue;
11010                }
11011                // Append the rest of the line and replace old reference with new one
11012                reindented_line.extend(chars);
11013                *line = Cow::Owned(reindented_line.clone());
11014                reindented_line.clear();
11015            }
11016        });
11017    }
11018
11019    pub fn convert_indentation_to_tabs(
11020        &mut self,
11021        _: &ConvertIndentationToTabs,
11022        window: &mut Window,
11023        cx: &mut Context<Self>,
11024    ) {
11025        let settings = self.buffer.read(cx).language_settings(cx);
11026        let tab_size = settings.tab_size.get() as usize;
11027
11028        self.manipulate_mutable_lines(window, cx, |lines| {
11029            // Allocates a reasonably sized buffer once for the whole loop
11030            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11031            // Avoids recomputing spaces that could be inserted many times
11032            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11033                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11034                .collect();
11035
11036            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11037                let mut chars = line.chars();
11038                let mut spaces_count = 0;
11039                let mut first_non_indent_char = None;
11040                let mut changed = false;
11041
11042                while let Some(ch) = chars.next() {
11043                    match ch {
11044                        ' ' => {
11045                            // Keep track of spaces. Append \t when we reach tab_size
11046                            spaces_count += 1;
11047                            changed = true;
11048                            if spaces_count == tab_size {
11049                                reindented_line.push('\t');
11050                                spaces_count = 0;
11051                            }
11052                        }
11053                        '\t' => {
11054                            reindented_line.push('\t');
11055                            spaces_count = 0;
11056                        }
11057                        _ => {
11058                            // Dont append it yet, we might have remaining spaces
11059                            first_non_indent_char = Some(ch);
11060                            break;
11061                        }
11062                    }
11063                }
11064
11065                if !changed {
11066                    reindented_line.clear();
11067                    continue;
11068                }
11069                // Remaining spaces that didn't make a full tab stop
11070                if spaces_count > 0 {
11071                    reindented_line.extend(&space_cache[spaces_count - 1]);
11072                }
11073                // If we consume an extra character that was not indentation, add it back
11074                if let Some(extra_char) = first_non_indent_char {
11075                    reindented_line.push(extra_char);
11076                }
11077                // Append the rest of the line and replace old reference with new one
11078                reindented_line.extend(chars);
11079                *line = Cow::Owned(reindented_line.clone());
11080                reindented_line.clear();
11081            }
11082        });
11083    }
11084
11085    pub fn convert_to_upper_case(
11086        &mut self,
11087        _: &ConvertToUpperCase,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| text.to_uppercase())
11092    }
11093
11094    pub fn convert_to_lower_case(
11095        &mut self,
11096        _: &ConvertToLowerCase,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099    ) {
11100        self.manipulate_text(window, cx, |text| text.to_lowercase())
11101    }
11102
11103    pub fn convert_to_title_case(
11104        &mut self,
11105        _: &ConvertToTitleCase,
11106        window: &mut Window,
11107        cx: &mut Context<Self>,
11108    ) {
11109        self.manipulate_text(window, cx, |text| {
11110            text.split('\n')
11111                .map(|line| line.to_case(Case::Title))
11112                .join("\n")
11113        })
11114    }
11115
11116    pub fn convert_to_snake_case(
11117        &mut self,
11118        _: &ConvertToSnakeCase,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11123    }
11124
11125    pub fn convert_to_kebab_case(
11126        &mut self,
11127        _: &ConvertToKebabCase,
11128        window: &mut Window,
11129        cx: &mut Context<Self>,
11130    ) {
11131        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11132    }
11133
11134    pub fn convert_to_upper_camel_case(
11135        &mut self,
11136        _: &ConvertToUpperCamelCase,
11137        window: &mut Window,
11138        cx: &mut Context<Self>,
11139    ) {
11140        self.manipulate_text(window, cx, |text| {
11141            text.split('\n')
11142                .map(|line| line.to_case(Case::UpperCamel))
11143                .join("\n")
11144        })
11145    }
11146
11147    pub fn convert_to_lower_camel_case(
11148        &mut self,
11149        _: &ConvertToLowerCamelCase,
11150        window: &mut Window,
11151        cx: &mut Context<Self>,
11152    ) {
11153        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11154    }
11155
11156    pub fn convert_to_opposite_case(
11157        &mut self,
11158        _: &ConvertToOppositeCase,
11159        window: &mut Window,
11160        cx: &mut Context<Self>,
11161    ) {
11162        self.manipulate_text(window, cx, |text| {
11163            text.chars()
11164                .fold(String::with_capacity(text.len()), |mut t, c| {
11165                    if c.is_uppercase() {
11166                        t.extend(c.to_lowercase());
11167                    } else {
11168                        t.extend(c.to_uppercase());
11169                    }
11170                    t
11171                })
11172        })
11173    }
11174
11175    pub fn convert_to_rot13(
11176        &mut self,
11177        _: &ConvertToRot13,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180    ) {
11181        self.manipulate_text(window, cx, |text| {
11182            text.chars()
11183                .map(|c| match c {
11184                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11185                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11186                    _ => c,
11187                })
11188                .collect()
11189        })
11190    }
11191
11192    pub fn convert_to_rot47(
11193        &mut self,
11194        _: &ConvertToRot47,
11195        window: &mut Window,
11196        cx: &mut Context<Self>,
11197    ) {
11198        self.manipulate_text(window, cx, |text| {
11199            text.chars()
11200                .map(|c| {
11201                    let code_point = c as u32;
11202                    if code_point >= 33 && code_point <= 126 {
11203                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11204                    }
11205                    c
11206                })
11207                .collect()
11208        })
11209    }
11210
11211    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11212    where
11213        Fn: FnMut(&str) -> String,
11214    {
11215        let buffer = self.buffer.read(cx).snapshot(cx);
11216
11217        let mut new_selections = Vec::new();
11218        let mut edits = Vec::new();
11219        let mut selection_adjustment = 0i32;
11220
11221        for selection in self.selections.all::<usize>(cx) {
11222            let selection_is_empty = selection.is_empty();
11223
11224            let (start, end) = if selection_is_empty {
11225                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11226                (word_range.start, word_range.end)
11227            } else {
11228                (selection.start, selection.end)
11229            };
11230
11231            let text = buffer.text_for_range(start..end).collect::<String>();
11232            let old_length = text.len() as i32;
11233            let text = callback(&text);
11234
11235            new_selections.push(Selection {
11236                start: (start as i32 - selection_adjustment) as usize,
11237                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11238                goal: SelectionGoal::None,
11239                ..selection
11240            });
11241
11242            selection_adjustment += old_length - text.len() as i32;
11243
11244            edits.push((start..end, text));
11245        }
11246
11247        self.transact(window, cx, |this, window, cx| {
11248            this.buffer.update(cx, |buffer, cx| {
11249                buffer.edit(edits, None, cx);
11250            });
11251
11252            this.change_selections(Default::default(), window, cx, |s| {
11253                s.select(new_selections);
11254            });
11255
11256            this.request_autoscroll(Autoscroll::fit(), cx);
11257        });
11258    }
11259
11260    pub fn move_selection_on_drop(
11261        &mut self,
11262        selection: &Selection<Anchor>,
11263        target: DisplayPoint,
11264        is_cut: bool,
11265        window: &mut Window,
11266        cx: &mut Context<Self>,
11267    ) {
11268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11269        let buffer = &display_map.buffer_snapshot;
11270        let mut edits = Vec::new();
11271        let insert_point = display_map
11272            .clip_point(target, Bias::Left)
11273            .to_point(&display_map);
11274        let text = buffer
11275            .text_for_range(selection.start..selection.end)
11276            .collect::<String>();
11277        if is_cut {
11278            edits.push(((selection.start..selection.end), String::new()));
11279        }
11280        let insert_anchor = buffer.anchor_before(insert_point);
11281        edits.push(((insert_anchor..insert_anchor), text));
11282        let last_edit_start = insert_anchor.bias_left(buffer);
11283        let last_edit_end = insert_anchor.bias_right(buffer);
11284        self.transact(window, cx, |this, window, cx| {
11285            this.buffer.update(cx, |buffer, cx| {
11286                buffer.edit(edits, None, cx);
11287            });
11288            this.change_selections(Default::default(), window, cx, |s| {
11289                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11290            });
11291        });
11292    }
11293
11294    pub fn clear_selection_drag_state(&mut self) {
11295        self.selection_drag_state = SelectionDragState::None;
11296    }
11297
11298    pub fn duplicate(
11299        &mut self,
11300        upwards: bool,
11301        whole_lines: bool,
11302        window: &mut Window,
11303        cx: &mut Context<Self>,
11304    ) {
11305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11306
11307        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11308        let buffer = &display_map.buffer_snapshot;
11309        let selections = self.selections.all::<Point>(cx);
11310
11311        let mut edits = Vec::new();
11312        let mut selections_iter = selections.iter().peekable();
11313        while let Some(selection) = selections_iter.next() {
11314            let mut rows = selection.spanned_rows(false, &display_map);
11315            // duplicate line-wise
11316            if whole_lines || selection.start == selection.end {
11317                // Avoid duplicating the same lines twice.
11318                while let Some(next_selection) = selections_iter.peek() {
11319                    let next_rows = next_selection.spanned_rows(false, &display_map);
11320                    if next_rows.start < rows.end {
11321                        rows.end = next_rows.end;
11322                        selections_iter.next().unwrap();
11323                    } else {
11324                        break;
11325                    }
11326                }
11327
11328                // Copy the text from the selected row region and splice it either at the start
11329                // or end of the region.
11330                let start = Point::new(rows.start.0, 0);
11331                let end = Point::new(
11332                    rows.end.previous_row().0,
11333                    buffer.line_len(rows.end.previous_row()),
11334                );
11335                let text = buffer
11336                    .text_for_range(start..end)
11337                    .chain(Some("\n"))
11338                    .collect::<String>();
11339                let insert_location = if upwards {
11340                    Point::new(rows.end.0, 0)
11341                } else {
11342                    start
11343                };
11344                edits.push((insert_location..insert_location, text));
11345            } else {
11346                // duplicate character-wise
11347                let start = selection.start;
11348                let end = selection.end;
11349                let text = buffer.text_for_range(start..end).collect::<String>();
11350                edits.push((selection.end..selection.end, text));
11351            }
11352        }
11353
11354        self.transact(window, cx, |this, _, cx| {
11355            this.buffer.update(cx, |buffer, cx| {
11356                buffer.edit(edits, None, cx);
11357            });
11358
11359            this.request_autoscroll(Autoscroll::fit(), cx);
11360        });
11361    }
11362
11363    pub fn duplicate_line_up(
11364        &mut self,
11365        _: &DuplicateLineUp,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        self.duplicate(true, true, window, cx);
11370    }
11371
11372    pub fn duplicate_line_down(
11373        &mut self,
11374        _: &DuplicateLineDown,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.duplicate(false, true, window, cx);
11379    }
11380
11381    pub fn duplicate_selection(
11382        &mut self,
11383        _: &DuplicateSelection,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386    ) {
11387        self.duplicate(false, false, window, cx);
11388    }
11389
11390    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11392        if self.mode.is_single_line() {
11393            cx.propagate();
11394            return;
11395        }
11396
11397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11398        let buffer = self.buffer.read(cx).snapshot(cx);
11399
11400        let mut edits = Vec::new();
11401        let mut unfold_ranges = Vec::new();
11402        let mut refold_creases = Vec::new();
11403
11404        let selections = self.selections.all::<Point>(cx);
11405        let mut selections = selections.iter().peekable();
11406        let mut contiguous_row_selections = Vec::new();
11407        let mut new_selections = Vec::new();
11408
11409        while let Some(selection) = selections.next() {
11410            // Find all the selections that span a contiguous row range
11411            let (start_row, end_row) = consume_contiguous_rows(
11412                &mut contiguous_row_selections,
11413                selection,
11414                &display_map,
11415                &mut selections,
11416            );
11417
11418            // Move the text spanned by the row range to be before the line preceding the row range
11419            if start_row.0 > 0 {
11420                let range_to_move = Point::new(
11421                    start_row.previous_row().0,
11422                    buffer.line_len(start_row.previous_row()),
11423                )
11424                    ..Point::new(
11425                        end_row.previous_row().0,
11426                        buffer.line_len(end_row.previous_row()),
11427                    );
11428                let insertion_point = display_map
11429                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11430                    .0;
11431
11432                // Don't move lines across excerpts
11433                if buffer
11434                    .excerpt_containing(insertion_point..range_to_move.end)
11435                    .is_some()
11436                {
11437                    let text = buffer
11438                        .text_for_range(range_to_move.clone())
11439                        .flat_map(|s| s.chars())
11440                        .skip(1)
11441                        .chain(['\n'])
11442                        .collect::<String>();
11443
11444                    edits.push((
11445                        buffer.anchor_after(range_to_move.start)
11446                            ..buffer.anchor_before(range_to_move.end),
11447                        String::new(),
11448                    ));
11449                    let insertion_anchor = buffer.anchor_after(insertion_point);
11450                    edits.push((insertion_anchor..insertion_anchor, text));
11451
11452                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11453
11454                    // Move selections up
11455                    new_selections.extend(contiguous_row_selections.drain(..).map(
11456                        |mut selection| {
11457                            selection.start.row -= row_delta;
11458                            selection.end.row -= row_delta;
11459                            selection
11460                        },
11461                    ));
11462
11463                    // Move folds up
11464                    unfold_ranges.push(range_to_move.clone());
11465                    for fold in display_map.folds_in_range(
11466                        buffer.anchor_before(range_to_move.start)
11467                            ..buffer.anchor_after(range_to_move.end),
11468                    ) {
11469                        let mut start = fold.range.start.to_point(&buffer);
11470                        let mut end = fold.range.end.to_point(&buffer);
11471                        start.row -= row_delta;
11472                        end.row -= row_delta;
11473                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11474                    }
11475                }
11476            }
11477
11478            // If we didn't move line(s), preserve the existing selections
11479            new_selections.append(&mut contiguous_row_selections);
11480        }
11481
11482        self.transact(window, cx, |this, window, cx| {
11483            this.unfold_ranges(&unfold_ranges, true, true, cx);
11484            this.buffer.update(cx, |buffer, cx| {
11485                for (range, text) in edits {
11486                    buffer.edit([(range, text)], None, cx);
11487                }
11488            });
11489            this.fold_creases(refold_creases, true, window, cx);
11490            this.change_selections(Default::default(), window, cx, |s| {
11491                s.select(new_selections);
11492            })
11493        });
11494    }
11495
11496    pub fn move_line_down(
11497        &mut self,
11498        _: &MoveLineDown,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11503        if self.mode.is_single_line() {
11504            cx.propagate();
11505            return;
11506        }
11507
11508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11509        let buffer = self.buffer.read(cx).snapshot(cx);
11510
11511        let mut edits = Vec::new();
11512        let mut unfold_ranges = Vec::new();
11513        let mut refold_creases = Vec::new();
11514
11515        let selections = self.selections.all::<Point>(cx);
11516        let mut selections = selections.iter().peekable();
11517        let mut contiguous_row_selections = Vec::new();
11518        let mut new_selections = Vec::new();
11519
11520        while let Some(selection) = selections.next() {
11521            // Find all the selections that span a contiguous row range
11522            let (start_row, end_row) = consume_contiguous_rows(
11523                &mut contiguous_row_selections,
11524                selection,
11525                &display_map,
11526                &mut selections,
11527            );
11528
11529            // Move the text spanned by the row range to be after the last line of the row range
11530            if end_row.0 <= buffer.max_point().row {
11531                let range_to_move =
11532                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11533                let insertion_point = display_map
11534                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11535                    .0;
11536
11537                // Don't move lines across excerpt boundaries
11538                if buffer
11539                    .excerpt_containing(range_to_move.start..insertion_point)
11540                    .is_some()
11541                {
11542                    let mut text = String::from("\n");
11543                    text.extend(buffer.text_for_range(range_to_move.clone()));
11544                    text.pop(); // Drop trailing newline
11545                    edits.push((
11546                        buffer.anchor_after(range_to_move.start)
11547                            ..buffer.anchor_before(range_to_move.end),
11548                        String::new(),
11549                    ));
11550                    let insertion_anchor = buffer.anchor_after(insertion_point);
11551                    edits.push((insertion_anchor..insertion_anchor, text));
11552
11553                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11554
11555                    // Move selections down
11556                    new_selections.extend(contiguous_row_selections.drain(..).map(
11557                        |mut selection| {
11558                            selection.start.row += row_delta;
11559                            selection.end.row += row_delta;
11560                            selection
11561                        },
11562                    ));
11563
11564                    // Move folds down
11565                    unfold_ranges.push(range_to_move.clone());
11566                    for fold in display_map.folds_in_range(
11567                        buffer.anchor_before(range_to_move.start)
11568                            ..buffer.anchor_after(range_to_move.end),
11569                    ) {
11570                        let mut start = fold.range.start.to_point(&buffer);
11571                        let mut end = fold.range.end.to_point(&buffer);
11572                        start.row += row_delta;
11573                        end.row += row_delta;
11574                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11575                    }
11576                }
11577            }
11578
11579            // If we didn't move line(s), preserve the existing selections
11580            new_selections.append(&mut contiguous_row_selections);
11581        }
11582
11583        self.transact(window, cx, |this, window, cx| {
11584            this.unfold_ranges(&unfold_ranges, true, true, cx);
11585            this.buffer.update(cx, |buffer, cx| {
11586                for (range, text) in edits {
11587                    buffer.edit([(range, text)], None, cx);
11588                }
11589            });
11590            this.fold_creases(refold_creases, true, window, cx);
11591            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11592        });
11593    }
11594
11595    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11597        let text_layout_details = &self.text_layout_details(window);
11598        self.transact(window, cx, |this, window, cx| {
11599            let edits = this.change_selections(Default::default(), window, cx, |s| {
11600                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11601                s.move_with(|display_map, selection| {
11602                    if !selection.is_empty() {
11603                        return;
11604                    }
11605
11606                    let mut head = selection.head();
11607                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11608                    if head.column() == display_map.line_len(head.row()) {
11609                        transpose_offset = display_map
11610                            .buffer_snapshot
11611                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11612                    }
11613
11614                    if transpose_offset == 0 {
11615                        return;
11616                    }
11617
11618                    *head.column_mut() += 1;
11619                    head = display_map.clip_point(head, Bias::Right);
11620                    let goal = SelectionGoal::HorizontalPosition(
11621                        display_map
11622                            .x_for_display_point(head, text_layout_details)
11623                            .into(),
11624                    );
11625                    selection.collapse_to(head, goal);
11626
11627                    let transpose_start = display_map
11628                        .buffer_snapshot
11629                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11630                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11631                        let transpose_end = display_map
11632                            .buffer_snapshot
11633                            .clip_offset(transpose_offset + 1, Bias::Right);
11634                        if let Some(ch) =
11635                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11636                        {
11637                            edits.push((transpose_start..transpose_offset, String::new()));
11638                            edits.push((transpose_end..transpose_end, ch.to_string()));
11639                        }
11640                    }
11641                });
11642                edits
11643            });
11644            this.buffer
11645                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11646            let selections = this.selections.all::<usize>(cx);
11647            this.change_selections(Default::default(), window, cx, |s| {
11648                s.select(selections);
11649            });
11650        });
11651    }
11652
11653    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11655        if self.mode.is_single_line() {
11656            cx.propagate();
11657            return;
11658        }
11659
11660        self.rewrap_impl(RewrapOptions::default(), cx)
11661    }
11662
11663    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11664        let buffer = self.buffer.read(cx).snapshot(cx);
11665        let selections = self.selections.all::<Point>(cx);
11666
11667        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11668        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11669            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11670                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11671                .peekable();
11672
11673            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11674                row
11675            } else {
11676                return Vec::new();
11677            };
11678
11679            let language_settings = buffer.language_settings_at(selection.head(), cx);
11680            let language_scope = buffer.language_scope_at(selection.head());
11681
11682            let indent_and_prefix_for_row =
11683                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11684                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11685                    let (comment_prefix, rewrap_prefix) =
11686                        if let Some(language_scope) = &language_scope {
11687                            let indent_end = Point::new(row, indent.len);
11688                            let comment_prefix = language_scope
11689                                .line_comment_prefixes()
11690                                .iter()
11691                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11692                                .map(|prefix| prefix.to_string());
11693                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11694                            let line_text_after_indent = buffer
11695                                .text_for_range(indent_end..line_end)
11696                                .collect::<String>();
11697                            let rewrap_prefix = language_scope
11698                                .rewrap_prefixes()
11699                                .iter()
11700                                .find_map(|prefix_regex| {
11701                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11702                                        if mat.start() == 0 {
11703                                            Some(mat.as_str().to_string())
11704                                        } else {
11705                                            None
11706                                        }
11707                                    })
11708                                })
11709                                .flatten();
11710                            (comment_prefix, rewrap_prefix)
11711                        } else {
11712                            (None, None)
11713                        };
11714                    (indent, comment_prefix, rewrap_prefix)
11715                };
11716
11717            let mut ranges = Vec::new();
11718            let from_empty_selection = selection.is_empty();
11719
11720            let mut current_range_start = first_row;
11721            let mut prev_row = first_row;
11722            let (
11723                mut current_range_indent,
11724                mut current_range_comment_prefix,
11725                mut current_range_rewrap_prefix,
11726            ) = indent_and_prefix_for_row(first_row);
11727
11728            for row in non_blank_rows_iter.skip(1) {
11729                let has_paragraph_break = row > prev_row + 1;
11730
11731                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11732                    indent_and_prefix_for_row(row);
11733
11734                let has_indent_change = row_indent != current_range_indent;
11735                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11736
11737                let has_boundary_change = has_comment_change
11738                    || row_rewrap_prefix.is_some()
11739                    || (has_indent_change && current_range_comment_prefix.is_some());
11740
11741                if has_paragraph_break || has_boundary_change {
11742                    ranges.push((
11743                        language_settings.clone(),
11744                        Point::new(current_range_start, 0)
11745                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11746                        current_range_indent,
11747                        current_range_comment_prefix.clone(),
11748                        current_range_rewrap_prefix.clone(),
11749                        from_empty_selection,
11750                    ));
11751                    current_range_start = row;
11752                    current_range_indent = row_indent;
11753                    current_range_comment_prefix = row_comment_prefix;
11754                    current_range_rewrap_prefix = row_rewrap_prefix;
11755                }
11756                prev_row = row;
11757            }
11758
11759            ranges.push((
11760                language_settings.clone(),
11761                Point::new(current_range_start, 0)
11762                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11763                current_range_indent,
11764                current_range_comment_prefix,
11765                current_range_rewrap_prefix,
11766                from_empty_selection,
11767            ));
11768
11769            ranges
11770        });
11771
11772        let mut edits = Vec::new();
11773        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11774
11775        for (
11776            language_settings,
11777            wrap_range,
11778            indent_size,
11779            comment_prefix,
11780            rewrap_prefix,
11781            from_empty_selection,
11782        ) in wrap_ranges
11783        {
11784            let mut start_row = wrap_range.start.row;
11785            let mut end_row = wrap_range.end.row;
11786
11787            // Skip selections that overlap with a range that has already been rewrapped.
11788            let selection_range = start_row..end_row;
11789            if rewrapped_row_ranges
11790                .iter()
11791                .any(|range| range.overlaps(&selection_range))
11792            {
11793                continue;
11794            }
11795
11796            let tab_size = language_settings.tab_size;
11797
11798            let indent_prefix = indent_size.chars().collect::<String>();
11799            let mut line_prefix = indent_prefix.clone();
11800            let mut inside_comment = false;
11801            if let Some(prefix) = &comment_prefix {
11802                line_prefix.push_str(prefix);
11803                inside_comment = true;
11804            }
11805            if let Some(prefix) = &rewrap_prefix {
11806                line_prefix.push_str(prefix);
11807            }
11808
11809            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11810                RewrapBehavior::InComments => inside_comment,
11811                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11812                RewrapBehavior::Anywhere => true,
11813            };
11814
11815            let should_rewrap = options.override_language_settings
11816                || allow_rewrap_based_on_language
11817                || self.hard_wrap.is_some();
11818            if !should_rewrap {
11819                continue;
11820            }
11821
11822            if from_empty_selection {
11823                'expand_upwards: while start_row > 0 {
11824                    let prev_row = start_row - 1;
11825                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11826                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11827                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11828                    {
11829                        start_row = prev_row;
11830                    } else {
11831                        break 'expand_upwards;
11832                    }
11833                }
11834
11835                'expand_downwards: while end_row < buffer.max_point().row {
11836                    let next_row = end_row + 1;
11837                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11838                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11839                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11840                    {
11841                        end_row = next_row;
11842                    } else {
11843                        break 'expand_downwards;
11844                    }
11845                }
11846            }
11847
11848            let start = Point::new(start_row, 0);
11849            let start_offset = start.to_offset(&buffer);
11850            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11851            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11852            let Some(lines_without_prefixes) = selection_text
11853                .lines()
11854                .enumerate()
11855                .map(|(ix, line)| {
11856                    let line_trimmed = line.trim_start();
11857                    if rewrap_prefix.is_some() && ix > 0 {
11858                        Ok(line_trimmed)
11859                    } else {
11860                        line_trimmed
11861                            .strip_prefix(&line_prefix.trim_start())
11862                            .with_context(|| {
11863                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11864                            })
11865                    }
11866                })
11867                .collect::<Result<Vec<_>, _>>()
11868                .log_err()
11869            else {
11870                continue;
11871            };
11872
11873            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11874                buffer
11875                    .language_settings_at(Point::new(start_row, 0), cx)
11876                    .preferred_line_length as usize
11877            });
11878
11879            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11880                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11881            } else {
11882                line_prefix.clone()
11883            };
11884
11885            let wrapped_text = wrap_with_prefix(
11886                line_prefix,
11887                subsequent_lines_prefix,
11888                lines_without_prefixes.join("\n"),
11889                wrap_column,
11890                tab_size,
11891                options.preserve_existing_whitespace,
11892            );
11893
11894            // TODO: should always use char-based diff while still supporting cursor behavior that
11895            // matches vim.
11896            let mut diff_options = DiffOptions::default();
11897            if options.override_language_settings {
11898                diff_options.max_word_diff_len = 0;
11899                diff_options.max_word_diff_line_count = 0;
11900            } else {
11901                diff_options.max_word_diff_len = usize::MAX;
11902                diff_options.max_word_diff_line_count = usize::MAX;
11903            }
11904
11905            for (old_range, new_text) in
11906                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11907            {
11908                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11909                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11910                edits.push((edit_start..edit_end, new_text));
11911            }
11912
11913            rewrapped_row_ranges.push(start_row..=end_row);
11914        }
11915
11916        self.buffer
11917            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11918    }
11919
11920    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11921        let mut text = String::new();
11922        let buffer = self.buffer.read(cx).snapshot(cx);
11923        let mut selections = self.selections.all::<Point>(cx);
11924        let mut clipboard_selections = Vec::with_capacity(selections.len());
11925        {
11926            let max_point = buffer.max_point();
11927            let mut is_first = true;
11928            for selection in &mut selections {
11929                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11930                if is_entire_line {
11931                    selection.start = Point::new(selection.start.row, 0);
11932                    if !selection.is_empty() && selection.end.column == 0 {
11933                        selection.end = cmp::min(max_point, selection.end);
11934                    } else {
11935                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11936                    }
11937                    selection.goal = SelectionGoal::None;
11938                }
11939                if is_first {
11940                    is_first = false;
11941                } else {
11942                    text += "\n";
11943                }
11944                let mut len = 0;
11945                for chunk in buffer.text_for_range(selection.start..selection.end) {
11946                    text.push_str(chunk);
11947                    len += chunk.len();
11948                }
11949                clipboard_selections.push(ClipboardSelection {
11950                    len,
11951                    is_entire_line,
11952                    first_line_indent: buffer
11953                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11954                        .len,
11955                });
11956            }
11957        }
11958
11959        self.transact(window, cx, |this, window, cx| {
11960            this.change_selections(Default::default(), window, cx, |s| {
11961                s.select(selections);
11962            });
11963            this.insert("", window, cx);
11964        });
11965        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11966    }
11967
11968    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11970        let item = self.cut_common(window, cx);
11971        cx.write_to_clipboard(item);
11972    }
11973
11974    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11976        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11977            s.move_with(|snapshot, sel| {
11978                if sel.is_empty() {
11979                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11980                }
11981            });
11982        });
11983        let item = self.cut_common(window, cx);
11984        cx.set_global(KillRing(item))
11985    }
11986
11987    pub fn kill_ring_yank(
11988        &mut self,
11989        _: &KillRingYank,
11990        window: &mut Window,
11991        cx: &mut Context<Self>,
11992    ) {
11993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11994        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11995            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11996                (kill_ring.text().to_string(), kill_ring.metadata_json())
11997            } else {
11998                return;
11999            }
12000        } else {
12001            return;
12002        };
12003        self.do_paste(&text, metadata, false, window, cx);
12004    }
12005
12006    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12007        self.do_copy(true, cx);
12008    }
12009
12010    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12011        self.do_copy(false, cx);
12012    }
12013
12014    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12015        let selections = self.selections.all::<Point>(cx);
12016        let buffer = self.buffer.read(cx).read(cx);
12017        let mut text = String::new();
12018
12019        let mut clipboard_selections = Vec::with_capacity(selections.len());
12020        {
12021            let max_point = buffer.max_point();
12022            let mut is_first = true;
12023            for selection in &selections {
12024                let mut start = selection.start;
12025                let mut end = selection.end;
12026                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12027                if is_entire_line {
12028                    start = Point::new(start.row, 0);
12029                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12030                }
12031
12032                let mut trimmed_selections = Vec::new();
12033                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12034                    let row = MultiBufferRow(start.row);
12035                    let first_indent = buffer.indent_size_for_line(row);
12036                    if first_indent.len == 0 || start.column > first_indent.len {
12037                        trimmed_selections.push(start..end);
12038                    } else {
12039                        trimmed_selections.push(
12040                            Point::new(row.0, first_indent.len)
12041                                ..Point::new(row.0, buffer.line_len(row)),
12042                        );
12043                        for row in start.row + 1..=end.row {
12044                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12045                            if row == end.row {
12046                                line_len = end.column;
12047                            }
12048                            if line_len == 0 {
12049                                trimmed_selections
12050                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12051                                continue;
12052                            }
12053                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12054                            if row_indent_size.len >= first_indent.len {
12055                                trimmed_selections.push(
12056                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12057                                );
12058                            } else {
12059                                trimmed_selections.clear();
12060                                trimmed_selections.push(start..end);
12061                                break;
12062                            }
12063                        }
12064                    }
12065                } else {
12066                    trimmed_selections.push(start..end);
12067                }
12068
12069                for trimmed_range in trimmed_selections {
12070                    if is_first {
12071                        is_first = false;
12072                    } else {
12073                        text += "\n";
12074                    }
12075                    let mut len = 0;
12076                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12077                        text.push_str(chunk);
12078                        len += chunk.len();
12079                    }
12080                    clipboard_selections.push(ClipboardSelection {
12081                        len,
12082                        is_entire_line,
12083                        first_line_indent: buffer
12084                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12085                            .len,
12086                    });
12087                }
12088            }
12089        }
12090
12091        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12092            text,
12093            clipboard_selections,
12094        ));
12095    }
12096
12097    pub fn do_paste(
12098        &mut self,
12099        text: &String,
12100        clipboard_selections: Option<Vec<ClipboardSelection>>,
12101        handle_entire_lines: bool,
12102        window: &mut Window,
12103        cx: &mut Context<Self>,
12104    ) {
12105        if self.read_only(cx) {
12106            return;
12107        }
12108
12109        let clipboard_text = Cow::Borrowed(text);
12110
12111        self.transact(window, cx, |this, window, cx| {
12112            if let Some(mut clipboard_selections) = clipboard_selections {
12113                let old_selections = this.selections.all::<usize>(cx);
12114                let all_selections_were_entire_line =
12115                    clipboard_selections.iter().all(|s| s.is_entire_line);
12116                let first_selection_indent_column =
12117                    clipboard_selections.first().map(|s| s.first_line_indent);
12118                if clipboard_selections.len() != old_selections.len() {
12119                    clipboard_selections.drain(..);
12120                }
12121                let cursor_offset = this.selections.last::<usize>(cx).head();
12122                let mut auto_indent_on_paste = true;
12123
12124                this.buffer.update(cx, |buffer, cx| {
12125                    let snapshot = buffer.read(cx);
12126                    auto_indent_on_paste = snapshot
12127                        .language_settings_at(cursor_offset, cx)
12128                        .auto_indent_on_paste;
12129
12130                    let mut start_offset = 0;
12131                    let mut edits = Vec::new();
12132                    let mut original_indent_columns = Vec::new();
12133                    for (ix, selection) in old_selections.iter().enumerate() {
12134                        let to_insert;
12135                        let entire_line;
12136                        let original_indent_column;
12137                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12138                            let end_offset = start_offset + clipboard_selection.len;
12139                            to_insert = &clipboard_text[start_offset..end_offset];
12140                            entire_line = clipboard_selection.is_entire_line;
12141                            start_offset = end_offset + 1;
12142                            original_indent_column = Some(clipboard_selection.first_line_indent);
12143                        } else {
12144                            to_insert = clipboard_text.as_str();
12145                            entire_line = all_selections_were_entire_line;
12146                            original_indent_column = first_selection_indent_column
12147                        }
12148
12149                        // If the corresponding selection was empty when this slice of the
12150                        // clipboard text was written, then the entire line containing the
12151                        // selection was copied. If this selection is also currently empty,
12152                        // then paste the line before the current line of the buffer.
12153                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12154                            let column = selection.start.to_point(&snapshot).column as usize;
12155                            let line_start = selection.start - column;
12156                            line_start..line_start
12157                        } else {
12158                            selection.range()
12159                        };
12160
12161                        edits.push((range, to_insert));
12162                        original_indent_columns.push(original_indent_column);
12163                    }
12164                    drop(snapshot);
12165
12166                    buffer.edit(
12167                        edits,
12168                        if auto_indent_on_paste {
12169                            Some(AutoindentMode::Block {
12170                                original_indent_columns,
12171                            })
12172                        } else {
12173                            None
12174                        },
12175                        cx,
12176                    );
12177                });
12178
12179                let selections = this.selections.all::<usize>(cx);
12180                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12181            } else {
12182                this.insert(&clipboard_text, window, cx);
12183            }
12184        });
12185    }
12186
12187    pub fn diff_clipboard_with_selection(
12188        &mut self,
12189        _: &DiffClipboardWithSelection,
12190        window: &mut Window,
12191        cx: &mut Context<Self>,
12192    ) {
12193        let selections = self.selections.all::<usize>(cx);
12194
12195        if selections.is_empty() {
12196            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12197            return;
12198        };
12199
12200        let clipboard_text = match cx.read_from_clipboard() {
12201            Some(item) => match item.entries().first() {
12202                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12203                _ => None,
12204            },
12205            None => None,
12206        };
12207
12208        let Some(clipboard_text) = clipboard_text else {
12209            log::warn!("Clipboard doesn't contain text.");
12210            return;
12211        };
12212
12213        window.dispatch_action(
12214            Box::new(DiffClipboardWithSelectionData {
12215                clipboard_text,
12216                editor: cx.entity(),
12217            }),
12218            cx,
12219        );
12220    }
12221
12222    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12223        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12224        if let Some(item) = cx.read_from_clipboard() {
12225            let entries = item.entries();
12226
12227            match entries.first() {
12228                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12229                // of all the pasted entries.
12230                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12231                    .do_paste(
12232                        clipboard_string.text(),
12233                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12234                        true,
12235                        window,
12236                        cx,
12237                    ),
12238                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12239            }
12240        }
12241    }
12242
12243    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12244        if self.read_only(cx) {
12245            return;
12246        }
12247
12248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12249
12250        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12251            if let Some((selections, _)) =
12252                self.selection_history.transaction(transaction_id).cloned()
12253            {
12254                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12255                    s.select_anchors(selections.to_vec());
12256                });
12257            } else {
12258                log::error!(
12259                    "No entry in selection_history found for undo. \
12260                     This may correspond to a bug where undo does not update the selection. \
12261                     If this is occurring, please add details to \
12262                     https://github.com/zed-industries/zed/issues/22692"
12263                );
12264            }
12265            self.request_autoscroll(Autoscroll::fit(), cx);
12266            self.unmark_text(window, cx);
12267            self.refresh_inline_completion(true, false, window, cx);
12268            cx.emit(EditorEvent::Edited { transaction_id });
12269            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12270        }
12271    }
12272
12273    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12274        if self.read_only(cx) {
12275            return;
12276        }
12277
12278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12279
12280        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12281            if let Some((_, Some(selections))) =
12282                self.selection_history.transaction(transaction_id).cloned()
12283            {
12284                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12285                    s.select_anchors(selections.to_vec());
12286                });
12287            } else {
12288                log::error!(
12289                    "No entry in selection_history found for redo. \
12290                     This may correspond to a bug where undo does not update the selection. \
12291                     If this is occurring, please add details to \
12292                     https://github.com/zed-industries/zed/issues/22692"
12293                );
12294            }
12295            self.request_autoscroll(Autoscroll::fit(), cx);
12296            self.unmark_text(window, cx);
12297            self.refresh_inline_completion(true, false, window, cx);
12298            cx.emit(EditorEvent::Edited { transaction_id });
12299        }
12300    }
12301
12302    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12303        self.buffer
12304            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12305    }
12306
12307    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12308        self.buffer
12309            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12310    }
12311
12312    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12314        self.change_selections(Default::default(), window, cx, |s| {
12315            s.move_with(|map, selection| {
12316                let cursor = if selection.is_empty() {
12317                    movement::left(map, selection.start)
12318                } else {
12319                    selection.start
12320                };
12321                selection.collapse_to(cursor, SelectionGoal::None);
12322            });
12323        })
12324    }
12325
12326    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12328        self.change_selections(Default::default(), window, cx, |s| {
12329            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12330        })
12331    }
12332
12333    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12335        self.change_selections(Default::default(), window, cx, |s| {
12336            s.move_with(|map, selection| {
12337                let cursor = if selection.is_empty() {
12338                    movement::right(map, selection.end)
12339                } else {
12340                    selection.end
12341                };
12342                selection.collapse_to(cursor, SelectionGoal::None)
12343            });
12344        })
12345    }
12346
12347    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12349        self.change_selections(Default::default(), window, cx, |s| {
12350            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12351        })
12352    }
12353
12354    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12355        if self.take_rename(true, window, cx).is_some() {
12356            return;
12357        }
12358
12359        if self.mode.is_single_line() {
12360            cx.propagate();
12361            return;
12362        }
12363
12364        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12365
12366        let text_layout_details = &self.text_layout_details(window);
12367        let selection_count = self.selections.count();
12368        let first_selection = self.selections.first_anchor();
12369
12370        self.change_selections(Default::default(), window, cx, |s| {
12371            s.move_with(|map, selection| {
12372                if !selection.is_empty() {
12373                    selection.goal = SelectionGoal::None;
12374                }
12375                let (cursor, goal) = movement::up(
12376                    map,
12377                    selection.start,
12378                    selection.goal,
12379                    false,
12380                    text_layout_details,
12381                );
12382                selection.collapse_to(cursor, goal);
12383            });
12384        });
12385
12386        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12387        {
12388            cx.propagate();
12389        }
12390    }
12391
12392    pub fn move_up_by_lines(
12393        &mut self,
12394        action: &MoveUpByLines,
12395        window: &mut Window,
12396        cx: &mut Context<Self>,
12397    ) {
12398        if self.take_rename(true, window, cx).is_some() {
12399            return;
12400        }
12401
12402        if self.mode.is_single_line() {
12403            cx.propagate();
12404            return;
12405        }
12406
12407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12408
12409        let text_layout_details = &self.text_layout_details(window);
12410
12411        self.change_selections(Default::default(), window, cx, |s| {
12412            s.move_with(|map, selection| {
12413                if !selection.is_empty() {
12414                    selection.goal = SelectionGoal::None;
12415                }
12416                let (cursor, goal) = movement::up_by_rows(
12417                    map,
12418                    selection.start,
12419                    action.lines,
12420                    selection.goal,
12421                    false,
12422                    text_layout_details,
12423                );
12424                selection.collapse_to(cursor, goal);
12425            });
12426        })
12427    }
12428
12429    pub fn move_down_by_lines(
12430        &mut self,
12431        action: &MoveDownByLines,
12432        window: &mut Window,
12433        cx: &mut Context<Self>,
12434    ) {
12435        if self.take_rename(true, window, cx).is_some() {
12436            return;
12437        }
12438
12439        if self.mode.is_single_line() {
12440            cx.propagate();
12441            return;
12442        }
12443
12444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12445
12446        let text_layout_details = &self.text_layout_details(window);
12447
12448        self.change_selections(Default::default(), window, cx, |s| {
12449            s.move_with(|map, selection| {
12450                if !selection.is_empty() {
12451                    selection.goal = SelectionGoal::None;
12452                }
12453                let (cursor, goal) = movement::down_by_rows(
12454                    map,
12455                    selection.start,
12456                    action.lines,
12457                    selection.goal,
12458                    false,
12459                    text_layout_details,
12460                );
12461                selection.collapse_to(cursor, goal);
12462            });
12463        })
12464    }
12465
12466    pub fn select_down_by_lines(
12467        &mut self,
12468        action: &SelectDownByLines,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12473        let text_layout_details = &self.text_layout_details(window);
12474        self.change_selections(Default::default(), window, cx, |s| {
12475            s.move_heads_with(|map, head, goal| {
12476                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12477            })
12478        })
12479    }
12480
12481    pub fn select_up_by_lines(
12482        &mut self,
12483        action: &SelectUpByLines,
12484        window: &mut Window,
12485        cx: &mut Context<Self>,
12486    ) {
12487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12488        let text_layout_details = &self.text_layout_details(window);
12489        self.change_selections(Default::default(), window, cx, |s| {
12490            s.move_heads_with(|map, head, goal| {
12491                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12492            })
12493        })
12494    }
12495
12496    pub fn select_page_up(
12497        &mut self,
12498        _: &SelectPageUp,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        let Some(row_count) = self.visible_row_count() else {
12503            return;
12504        };
12505
12506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12507
12508        let text_layout_details = &self.text_layout_details(window);
12509
12510        self.change_selections(Default::default(), window, cx, |s| {
12511            s.move_heads_with(|map, head, goal| {
12512                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12513            })
12514        })
12515    }
12516
12517    pub fn move_page_up(
12518        &mut self,
12519        action: &MovePageUp,
12520        window: &mut Window,
12521        cx: &mut Context<Self>,
12522    ) {
12523        if self.take_rename(true, window, cx).is_some() {
12524            return;
12525        }
12526
12527        if self
12528            .context_menu
12529            .borrow_mut()
12530            .as_mut()
12531            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12532            .unwrap_or(false)
12533        {
12534            return;
12535        }
12536
12537        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12538            cx.propagate();
12539            return;
12540        }
12541
12542        let Some(row_count) = self.visible_row_count() else {
12543            return;
12544        };
12545
12546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12547
12548        let effects = if action.center_cursor {
12549            SelectionEffects::scroll(Autoscroll::center())
12550        } else {
12551            SelectionEffects::default()
12552        };
12553
12554        let text_layout_details = &self.text_layout_details(window);
12555
12556        self.change_selections(effects, window, cx, |s| {
12557            s.move_with(|map, selection| {
12558                if !selection.is_empty() {
12559                    selection.goal = SelectionGoal::None;
12560                }
12561                let (cursor, goal) = movement::up_by_rows(
12562                    map,
12563                    selection.end,
12564                    row_count,
12565                    selection.goal,
12566                    false,
12567                    text_layout_details,
12568                );
12569                selection.collapse_to(cursor, goal);
12570            });
12571        });
12572    }
12573
12574    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12576        let text_layout_details = &self.text_layout_details(window);
12577        self.change_selections(Default::default(), window, cx, |s| {
12578            s.move_heads_with(|map, head, goal| {
12579                movement::up(map, head, goal, false, text_layout_details)
12580            })
12581        })
12582    }
12583
12584    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12585        self.take_rename(true, window, cx);
12586
12587        if self.mode.is_single_line() {
12588            cx.propagate();
12589            return;
12590        }
12591
12592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12593
12594        let text_layout_details = &self.text_layout_details(window);
12595        let selection_count = self.selections.count();
12596        let first_selection = self.selections.first_anchor();
12597
12598        self.change_selections(Default::default(), window, cx, |s| {
12599            s.move_with(|map, selection| {
12600                if !selection.is_empty() {
12601                    selection.goal = SelectionGoal::None;
12602                }
12603                let (cursor, goal) = movement::down(
12604                    map,
12605                    selection.end,
12606                    selection.goal,
12607                    false,
12608                    text_layout_details,
12609                );
12610                selection.collapse_to(cursor, goal);
12611            });
12612        });
12613
12614        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12615        {
12616            cx.propagate();
12617        }
12618    }
12619
12620    pub fn select_page_down(
12621        &mut self,
12622        _: &SelectPageDown,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) {
12626        let Some(row_count) = self.visible_row_count() else {
12627            return;
12628        };
12629
12630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12631
12632        let text_layout_details = &self.text_layout_details(window);
12633
12634        self.change_selections(Default::default(), window, cx, |s| {
12635            s.move_heads_with(|map, head, goal| {
12636                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12637            })
12638        })
12639    }
12640
12641    pub fn move_page_down(
12642        &mut self,
12643        action: &MovePageDown,
12644        window: &mut Window,
12645        cx: &mut Context<Self>,
12646    ) {
12647        if self.take_rename(true, window, cx).is_some() {
12648            return;
12649        }
12650
12651        if self
12652            .context_menu
12653            .borrow_mut()
12654            .as_mut()
12655            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12656            .unwrap_or(false)
12657        {
12658            return;
12659        }
12660
12661        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12662            cx.propagate();
12663            return;
12664        }
12665
12666        let Some(row_count) = self.visible_row_count() else {
12667            return;
12668        };
12669
12670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12671
12672        let effects = if action.center_cursor {
12673            SelectionEffects::scroll(Autoscroll::center())
12674        } else {
12675            SelectionEffects::default()
12676        };
12677
12678        let text_layout_details = &self.text_layout_details(window);
12679        self.change_selections(effects, window, cx, |s| {
12680            s.move_with(|map, selection| {
12681                if !selection.is_empty() {
12682                    selection.goal = SelectionGoal::None;
12683                }
12684                let (cursor, goal) = movement::down_by_rows(
12685                    map,
12686                    selection.end,
12687                    row_count,
12688                    selection.goal,
12689                    false,
12690                    text_layout_details,
12691                );
12692                selection.collapse_to(cursor, goal);
12693            });
12694        });
12695    }
12696
12697    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12699        let text_layout_details = &self.text_layout_details(window);
12700        self.change_selections(Default::default(), window, cx, |s| {
12701            s.move_heads_with(|map, head, goal| {
12702                movement::down(map, head, goal, false, text_layout_details)
12703            })
12704        });
12705    }
12706
12707    pub fn context_menu_first(
12708        &mut self,
12709        _: &ContextMenuFirst,
12710        window: &mut Window,
12711        cx: &mut Context<Self>,
12712    ) {
12713        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12714            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12715        }
12716    }
12717
12718    pub fn context_menu_prev(
12719        &mut self,
12720        _: &ContextMenuPrevious,
12721        window: &mut Window,
12722        cx: &mut Context<Self>,
12723    ) {
12724        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12725            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12726        }
12727    }
12728
12729    pub fn context_menu_next(
12730        &mut self,
12731        _: &ContextMenuNext,
12732        window: &mut Window,
12733        cx: &mut Context<Self>,
12734    ) {
12735        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12736            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12737        }
12738    }
12739
12740    pub fn context_menu_last(
12741        &mut self,
12742        _: &ContextMenuLast,
12743        window: &mut Window,
12744        cx: &mut Context<Self>,
12745    ) {
12746        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12747            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12748        }
12749    }
12750
12751    pub fn signature_help_prev(
12752        &mut self,
12753        _: &SignatureHelpPrevious,
12754        _: &mut Window,
12755        cx: &mut Context<Self>,
12756    ) {
12757        if let Some(popover) = self.signature_help_state.popover_mut() {
12758            if popover.current_signature == 0 {
12759                popover.current_signature = popover.signatures.len() - 1;
12760            } else {
12761                popover.current_signature -= 1;
12762            }
12763            cx.notify();
12764        }
12765    }
12766
12767    pub fn signature_help_next(
12768        &mut self,
12769        _: &SignatureHelpNext,
12770        _: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) {
12773        if let Some(popover) = self.signature_help_state.popover_mut() {
12774            if popover.current_signature + 1 == popover.signatures.len() {
12775                popover.current_signature = 0;
12776            } else {
12777                popover.current_signature += 1;
12778            }
12779            cx.notify();
12780        }
12781    }
12782
12783    pub fn move_to_previous_word_start(
12784        &mut self,
12785        _: &MoveToPreviousWordStart,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12790        self.change_selections(Default::default(), window, cx, |s| {
12791            s.move_cursors_with(|map, head, _| {
12792                (
12793                    movement::previous_word_start(map, head),
12794                    SelectionGoal::None,
12795                )
12796            });
12797        })
12798    }
12799
12800    pub fn move_to_previous_subword_start(
12801        &mut self,
12802        _: &MoveToPreviousSubwordStart,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12807        self.change_selections(Default::default(), window, cx, |s| {
12808            s.move_cursors_with(|map, head, _| {
12809                (
12810                    movement::previous_subword_start(map, head),
12811                    SelectionGoal::None,
12812                )
12813            });
12814        })
12815    }
12816
12817    pub fn select_to_previous_word_start(
12818        &mut self,
12819        _: &SelectToPreviousWordStart,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_heads_with(|map, head, _| {
12826                (
12827                    movement::previous_word_start(map, head),
12828                    SelectionGoal::None,
12829                )
12830            });
12831        })
12832    }
12833
12834    pub fn select_to_previous_subword_start(
12835        &mut self,
12836        _: &SelectToPreviousSubwordStart,
12837        window: &mut Window,
12838        cx: &mut Context<Self>,
12839    ) {
12840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12841        self.change_selections(Default::default(), window, cx, |s| {
12842            s.move_heads_with(|map, head, _| {
12843                (
12844                    movement::previous_subword_start(map, head),
12845                    SelectionGoal::None,
12846                )
12847            });
12848        })
12849    }
12850
12851    pub fn delete_to_previous_word_start(
12852        &mut self,
12853        action: &DeleteToPreviousWordStart,
12854        window: &mut Window,
12855        cx: &mut Context<Self>,
12856    ) {
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12858        self.transact(window, cx, |this, window, cx| {
12859            this.select_autoclose_pair(window, cx);
12860            this.change_selections(Default::default(), window, cx, |s| {
12861                s.move_with(|map, selection| {
12862                    if selection.is_empty() {
12863                        let cursor = if action.ignore_newlines {
12864                            movement::previous_word_start(map, selection.head())
12865                        } else {
12866                            movement::previous_word_start_or_newline(map, selection.head())
12867                        };
12868                        selection.set_head(cursor, SelectionGoal::None);
12869                    }
12870                });
12871            });
12872            this.insert("", window, cx);
12873        });
12874    }
12875
12876    pub fn delete_to_previous_subword_start(
12877        &mut self,
12878        _: &DeleteToPreviousSubwordStart,
12879        window: &mut Window,
12880        cx: &mut Context<Self>,
12881    ) {
12882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12883        self.transact(window, cx, |this, window, cx| {
12884            this.select_autoclose_pair(window, cx);
12885            this.change_selections(Default::default(), window, cx, |s| {
12886                s.move_with(|map, selection| {
12887                    if selection.is_empty() {
12888                        let cursor = movement::previous_subword_start(map, selection.head());
12889                        selection.set_head(cursor, SelectionGoal::None);
12890                    }
12891                });
12892            });
12893            this.insert("", window, cx);
12894        });
12895    }
12896
12897    pub fn move_to_next_word_end(
12898        &mut self,
12899        _: &MoveToNextWordEnd,
12900        window: &mut Window,
12901        cx: &mut Context<Self>,
12902    ) {
12903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12904        self.change_selections(Default::default(), window, cx, |s| {
12905            s.move_cursors_with(|map, head, _| {
12906                (movement::next_word_end(map, head), SelectionGoal::None)
12907            });
12908        })
12909    }
12910
12911    pub fn move_to_next_subword_end(
12912        &mut self,
12913        _: &MoveToNextSubwordEnd,
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                (movement::next_subword_end(map, head), SelectionGoal::None)
12921            });
12922        })
12923    }
12924
12925    pub fn select_to_next_word_end(
12926        &mut self,
12927        _: &SelectToNextWordEnd,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12932        self.change_selections(Default::default(), window, cx, |s| {
12933            s.move_heads_with(|map, head, _| {
12934                (movement::next_word_end(map, head), SelectionGoal::None)
12935            });
12936        })
12937    }
12938
12939    pub fn select_to_next_subword_end(
12940        &mut self,
12941        _: &SelectToNextSubwordEnd,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_heads_with(|map, head, _| {
12948                (movement::next_subword_end(map, head), SelectionGoal::None)
12949            });
12950        })
12951    }
12952
12953    pub fn delete_to_next_word_end(
12954        &mut self,
12955        action: &DeleteToNextWordEnd,
12956        window: &mut Window,
12957        cx: &mut Context<Self>,
12958    ) {
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12960        self.transact(window, cx, |this, window, cx| {
12961            this.change_selections(Default::default(), window, cx, |s| {
12962                s.move_with(|map, selection| {
12963                    if selection.is_empty() {
12964                        let cursor = if action.ignore_newlines {
12965                            movement::next_word_end(map, selection.head())
12966                        } else {
12967                            movement::next_word_end_or_newline(map, selection.head())
12968                        };
12969                        selection.set_head(cursor, SelectionGoal::None);
12970                    }
12971                });
12972            });
12973            this.insert("", window, cx);
12974        });
12975    }
12976
12977    pub fn delete_to_next_subword_end(
12978        &mut self,
12979        _: &DeleteToNextSubwordEnd,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12984        self.transact(window, cx, |this, window, cx| {
12985            this.change_selections(Default::default(), window, cx, |s| {
12986                s.move_with(|map, selection| {
12987                    if selection.is_empty() {
12988                        let cursor = movement::next_subword_end(map, selection.head());
12989                        selection.set_head(cursor, SelectionGoal::None);
12990                    }
12991                });
12992            });
12993            this.insert("", window, cx);
12994        });
12995    }
12996
12997    pub fn move_to_beginning_of_line(
12998        &mut self,
12999        action: &MoveToBeginningOfLine,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) {
13003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13004        self.change_selections(Default::default(), window, cx, |s| {
13005            s.move_cursors_with(|map, head, _| {
13006                (
13007                    movement::indented_line_beginning(
13008                        map,
13009                        head,
13010                        action.stop_at_soft_wraps,
13011                        action.stop_at_indent,
13012                    ),
13013                    SelectionGoal::None,
13014                )
13015            });
13016        })
13017    }
13018
13019    pub fn select_to_beginning_of_line(
13020        &mut self,
13021        action: &SelectToBeginningOfLine,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_heads_with(|map, head, _| {
13028                (
13029                    movement::indented_line_beginning(
13030                        map,
13031                        head,
13032                        action.stop_at_soft_wraps,
13033                        action.stop_at_indent,
13034                    ),
13035                    SelectionGoal::None,
13036                )
13037            });
13038        });
13039    }
13040
13041    pub fn delete_to_beginning_of_line(
13042        &mut self,
13043        action: &DeleteToBeginningOfLine,
13044        window: &mut Window,
13045        cx: &mut Context<Self>,
13046    ) {
13047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13048        self.transact(window, cx, |this, window, cx| {
13049            this.change_selections(Default::default(), window, cx, |s| {
13050                s.move_with(|_, selection| {
13051                    selection.reversed = true;
13052                });
13053            });
13054
13055            this.select_to_beginning_of_line(
13056                &SelectToBeginningOfLine {
13057                    stop_at_soft_wraps: false,
13058                    stop_at_indent: action.stop_at_indent,
13059                },
13060                window,
13061                cx,
13062            );
13063            this.backspace(&Backspace, window, cx);
13064        });
13065    }
13066
13067    pub fn move_to_end_of_line(
13068        &mut self,
13069        action: &MoveToEndOfLine,
13070        window: &mut Window,
13071        cx: &mut Context<Self>,
13072    ) {
13073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13074        self.change_selections(Default::default(), window, cx, |s| {
13075            s.move_cursors_with(|map, head, _| {
13076                (
13077                    movement::line_end(map, head, action.stop_at_soft_wraps),
13078                    SelectionGoal::None,
13079                )
13080            });
13081        })
13082    }
13083
13084    pub fn select_to_end_of_line(
13085        &mut self,
13086        action: &SelectToEndOfLine,
13087        window: &mut Window,
13088        cx: &mut Context<Self>,
13089    ) {
13090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13091        self.change_selections(Default::default(), window, cx, |s| {
13092            s.move_heads_with(|map, head, _| {
13093                (
13094                    movement::line_end(map, head, action.stop_at_soft_wraps),
13095                    SelectionGoal::None,
13096                )
13097            });
13098        })
13099    }
13100
13101    pub fn delete_to_end_of_line(
13102        &mut self,
13103        _: &DeleteToEndOfLine,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13108        self.transact(window, cx, |this, window, cx| {
13109            this.select_to_end_of_line(
13110                &SelectToEndOfLine {
13111                    stop_at_soft_wraps: false,
13112                },
13113                window,
13114                cx,
13115            );
13116            this.delete(&Delete, window, cx);
13117        });
13118    }
13119
13120    pub fn cut_to_end_of_line(
13121        &mut self,
13122        _: &CutToEndOfLine,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13127        self.transact(window, cx, |this, window, cx| {
13128            this.select_to_end_of_line(
13129                &SelectToEndOfLine {
13130                    stop_at_soft_wraps: false,
13131                },
13132                window,
13133                cx,
13134            );
13135            this.cut(&Cut, window, cx);
13136        });
13137    }
13138
13139    pub fn move_to_start_of_paragraph(
13140        &mut self,
13141        _: &MoveToStartOfParagraph,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13146            cx.propagate();
13147            return;
13148        }
13149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13150        self.change_selections(Default::default(), window, cx, |s| {
13151            s.move_with(|map, selection| {
13152                selection.collapse_to(
13153                    movement::start_of_paragraph(map, selection.head(), 1),
13154                    SelectionGoal::None,
13155                )
13156            });
13157        })
13158    }
13159
13160    pub fn move_to_end_of_paragraph(
13161        &mut self,
13162        _: &MoveToEndOfParagraph,
13163        window: &mut Window,
13164        cx: &mut Context<Self>,
13165    ) {
13166        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13167            cx.propagate();
13168            return;
13169        }
13170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13171        self.change_selections(Default::default(), window, cx, |s| {
13172            s.move_with(|map, selection| {
13173                selection.collapse_to(
13174                    movement::end_of_paragraph(map, selection.head(), 1),
13175                    SelectionGoal::None,
13176                )
13177            });
13178        })
13179    }
13180
13181    pub fn select_to_start_of_paragraph(
13182        &mut self,
13183        _: &SelectToStartOfParagraph,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13188            cx.propagate();
13189            return;
13190        }
13191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13192        self.change_selections(Default::default(), window, cx, |s| {
13193            s.move_heads_with(|map, head, _| {
13194                (
13195                    movement::start_of_paragraph(map, head, 1),
13196                    SelectionGoal::None,
13197                )
13198            });
13199        })
13200    }
13201
13202    pub fn select_to_end_of_paragraph(
13203        &mut self,
13204        _: &SelectToEndOfParagraph,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13209            cx.propagate();
13210            return;
13211        }
13212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13213        self.change_selections(Default::default(), window, cx, |s| {
13214            s.move_heads_with(|map, head, _| {
13215                (
13216                    movement::end_of_paragraph(map, head, 1),
13217                    SelectionGoal::None,
13218                )
13219            });
13220        })
13221    }
13222
13223    pub fn move_to_start_of_excerpt(
13224        &mut self,
13225        _: &MoveToStartOfExcerpt,
13226        window: &mut Window,
13227        cx: &mut Context<Self>,
13228    ) {
13229        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13230            cx.propagate();
13231            return;
13232        }
13233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13234        self.change_selections(Default::default(), window, cx, |s| {
13235            s.move_with(|map, selection| {
13236                selection.collapse_to(
13237                    movement::start_of_excerpt(
13238                        map,
13239                        selection.head(),
13240                        workspace::searchable::Direction::Prev,
13241                    ),
13242                    SelectionGoal::None,
13243                )
13244            });
13245        })
13246    }
13247
13248    pub fn move_to_start_of_next_excerpt(
13249        &mut self,
13250        _: &MoveToStartOfNextExcerpt,
13251        window: &mut Window,
13252        cx: &mut Context<Self>,
13253    ) {
13254        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13255            cx.propagate();
13256            return;
13257        }
13258
13259        self.change_selections(Default::default(), window, cx, |s| {
13260            s.move_with(|map, selection| {
13261                selection.collapse_to(
13262                    movement::start_of_excerpt(
13263                        map,
13264                        selection.head(),
13265                        workspace::searchable::Direction::Next,
13266                    ),
13267                    SelectionGoal::None,
13268                )
13269            });
13270        })
13271    }
13272
13273    pub fn move_to_end_of_excerpt(
13274        &mut self,
13275        _: &MoveToEndOfExcerpt,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13280            cx.propagate();
13281            return;
13282        }
13283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13284        self.change_selections(Default::default(), window, cx, |s| {
13285            s.move_with(|map, selection| {
13286                selection.collapse_to(
13287                    movement::end_of_excerpt(
13288                        map,
13289                        selection.head(),
13290                        workspace::searchable::Direction::Next,
13291                    ),
13292                    SelectionGoal::None,
13293                )
13294            });
13295        })
13296    }
13297
13298    pub fn move_to_end_of_previous_excerpt(
13299        &mut self,
13300        _: &MoveToEndOfPreviousExcerpt,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13305            cx.propagate();
13306            return;
13307        }
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_with(|map, selection| {
13311                selection.collapse_to(
13312                    movement::end_of_excerpt(
13313                        map,
13314                        selection.head(),
13315                        workspace::searchable::Direction::Prev,
13316                    ),
13317                    SelectionGoal::None,
13318                )
13319            });
13320        })
13321    }
13322
13323    pub fn select_to_start_of_excerpt(
13324        &mut self,
13325        _: &SelectToStartOfExcerpt,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13330            cx.propagate();
13331            return;
13332        }
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        self.change_selections(Default::default(), window, cx, |s| {
13335            s.move_heads_with(|map, head, _| {
13336                (
13337                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13338                    SelectionGoal::None,
13339                )
13340            });
13341        })
13342    }
13343
13344    pub fn select_to_start_of_next_excerpt(
13345        &mut self,
13346        _: &SelectToStartOfNextExcerpt,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13351            cx.propagate();
13352            return;
13353        }
13354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13355        self.change_selections(Default::default(), window, cx, |s| {
13356            s.move_heads_with(|map, head, _| {
13357                (
13358                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13359                    SelectionGoal::None,
13360                )
13361            });
13362        })
13363    }
13364
13365    pub fn select_to_end_of_excerpt(
13366        &mut self,
13367        _: &SelectToEndOfExcerpt,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13372            cx.propagate();
13373            return;
13374        }
13375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13376        self.change_selections(Default::default(), window, cx, |s| {
13377            s.move_heads_with(|map, head, _| {
13378                (
13379                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13380                    SelectionGoal::None,
13381                )
13382            });
13383        })
13384    }
13385
13386    pub fn select_to_end_of_previous_excerpt(
13387        &mut self,
13388        _: &SelectToEndOfPreviousExcerpt,
13389        window: &mut Window,
13390        cx: &mut Context<Self>,
13391    ) {
13392        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13393            cx.propagate();
13394            return;
13395        }
13396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13397        self.change_selections(Default::default(), window, cx, |s| {
13398            s.move_heads_with(|map, head, _| {
13399                (
13400                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13401                    SelectionGoal::None,
13402                )
13403            });
13404        })
13405    }
13406
13407    pub fn move_to_beginning(
13408        &mut self,
13409        _: &MoveToBeginning,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13414            cx.propagate();
13415            return;
13416        }
13417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13418        self.change_selections(Default::default(), window, cx, |s| {
13419            s.select_ranges(vec![0..0]);
13420        });
13421    }
13422
13423    pub fn select_to_beginning(
13424        &mut self,
13425        _: &SelectToBeginning,
13426        window: &mut Window,
13427        cx: &mut Context<Self>,
13428    ) {
13429        let mut selection = self.selections.last::<Point>(cx);
13430        selection.set_head(Point::zero(), SelectionGoal::None);
13431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13432        self.change_selections(Default::default(), window, cx, |s| {
13433            s.select(vec![selection]);
13434        });
13435    }
13436
13437    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13438        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13439            cx.propagate();
13440            return;
13441        }
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        let cursor = self.buffer.read(cx).read(cx).len();
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.select_ranges(vec![cursor..cursor])
13446        });
13447    }
13448
13449    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13450        self.nav_history = nav_history;
13451    }
13452
13453    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13454        self.nav_history.as_ref()
13455    }
13456
13457    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13458        self.push_to_nav_history(
13459            self.selections.newest_anchor().head(),
13460            None,
13461            false,
13462            true,
13463            cx,
13464        );
13465    }
13466
13467    fn push_to_nav_history(
13468        &mut self,
13469        cursor_anchor: Anchor,
13470        new_position: Option<Point>,
13471        is_deactivate: bool,
13472        always: bool,
13473        cx: &mut Context<Self>,
13474    ) {
13475        if let Some(nav_history) = self.nav_history.as_mut() {
13476            let buffer = self.buffer.read(cx).read(cx);
13477            let cursor_position = cursor_anchor.to_point(&buffer);
13478            let scroll_state = self.scroll_manager.anchor();
13479            let scroll_top_row = scroll_state.top_row(&buffer);
13480            drop(buffer);
13481
13482            if let Some(new_position) = new_position {
13483                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13484                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13485                    return;
13486                }
13487            }
13488
13489            nav_history.push(
13490                Some(NavigationData {
13491                    cursor_anchor,
13492                    cursor_position,
13493                    scroll_anchor: scroll_state,
13494                    scroll_top_row,
13495                }),
13496                cx,
13497            );
13498            cx.emit(EditorEvent::PushedToNavHistory {
13499                anchor: cursor_anchor,
13500                is_deactivate,
13501            })
13502        }
13503    }
13504
13505    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507        let buffer = self.buffer.read(cx).snapshot(cx);
13508        let mut selection = self.selections.first::<usize>(cx);
13509        selection.set_head(buffer.len(), SelectionGoal::None);
13510        self.change_selections(Default::default(), window, cx, |s| {
13511            s.select(vec![selection]);
13512        });
13513    }
13514
13515    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13517        let end = self.buffer.read(cx).read(cx).len();
13518        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13519            s.select_ranges(vec![0..end]);
13520        });
13521    }
13522
13523    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13526        let mut selections = self.selections.all::<Point>(cx);
13527        let max_point = display_map.buffer_snapshot.max_point();
13528        for selection in &mut selections {
13529            let rows = selection.spanned_rows(true, &display_map);
13530            selection.start = Point::new(rows.start.0, 0);
13531            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13532            selection.reversed = false;
13533        }
13534        self.change_selections(Default::default(), window, cx, |s| {
13535            s.select(selections);
13536        });
13537    }
13538
13539    pub fn split_selection_into_lines(
13540        &mut self,
13541        _: &SplitSelectionIntoLines,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) {
13545        let selections = self
13546            .selections
13547            .all::<Point>(cx)
13548            .into_iter()
13549            .map(|selection| selection.start..selection.end)
13550            .collect::<Vec<_>>();
13551        self.unfold_ranges(&selections, true, true, cx);
13552
13553        let mut new_selection_ranges = Vec::new();
13554        {
13555            let buffer = self.buffer.read(cx).read(cx);
13556            for selection in selections {
13557                for row in selection.start.row..selection.end.row {
13558                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13559                    new_selection_ranges.push(cursor..cursor);
13560                }
13561
13562                let is_multiline_selection = selection.start.row != selection.end.row;
13563                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13564                // so this action feels more ergonomic when paired with other selection operations
13565                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13566                if !should_skip_last {
13567                    new_selection_ranges.push(selection.end..selection.end);
13568                }
13569            }
13570        }
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.select_ranges(new_selection_ranges);
13573        });
13574    }
13575
13576    pub fn add_selection_above(
13577        &mut self,
13578        _: &AddSelectionAbove,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        self.add_selection(true, window, cx);
13583    }
13584
13585    pub fn add_selection_below(
13586        &mut self,
13587        _: &AddSelectionBelow,
13588        window: &mut Window,
13589        cx: &mut Context<Self>,
13590    ) {
13591        self.add_selection(false, window, cx);
13592    }
13593
13594    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13596
13597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13598        let all_selections = self.selections.all::<Point>(cx);
13599        let text_layout_details = self.text_layout_details(window);
13600
13601        let (mut columnar_selections, new_selections_to_columnarize) = {
13602            if let Some(state) = self.add_selections_state.as_ref() {
13603                let columnar_selection_ids: HashSet<_> = state
13604                    .groups
13605                    .iter()
13606                    .flat_map(|group| group.stack.iter())
13607                    .copied()
13608                    .collect();
13609
13610                all_selections
13611                    .into_iter()
13612                    .partition(|s| columnar_selection_ids.contains(&s.id))
13613            } else {
13614                (Vec::new(), all_selections)
13615            }
13616        };
13617
13618        let mut state = self
13619            .add_selections_state
13620            .take()
13621            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13622
13623        for selection in new_selections_to_columnarize {
13624            let range = selection.display_range(&display_map).sorted();
13625            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13626            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13627            let positions = start_x.min(end_x)..start_x.max(end_x);
13628            let mut stack = Vec::new();
13629            for row in range.start.row().0..=range.end.row().0 {
13630                if let Some(selection) = self.selections.build_columnar_selection(
13631                    &display_map,
13632                    DisplayRow(row),
13633                    &positions,
13634                    selection.reversed,
13635                    &text_layout_details,
13636                ) {
13637                    stack.push(selection.id);
13638                    columnar_selections.push(selection);
13639                }
13640            }
13641            if !stack.is_empty() {
13642                if above {
13643                    stack.reverse();
13644                }
13645                state.groups.push(AddSelectionsGroup { above, stack });
13646            }
13647        }
13648
13649        let mut final_selections = Vec::new();
13650        let end_row = if above {
13651            DisplayRow(0)
13652        } else {
13653            display_map.max_point().row()
13654        };
13655
13656        let mut last_added_item_per_group = HashMap::default();
13657        for group in state.groups.iter_mut() {
13658            if let Some(last_id) = group.stack.last() {
13659                last_added_item_per_group.insert(*last_id, group);
13660            }
13661        }
13662
13663        for selection in columnar_selections {
13664            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13665                if above == group.above {
13666                    let range = selection.display_range(&display_map).sorted();
13667                    debug_assert_eq!(range.start.row(), range.end.row());
13668                    let mut row = range.start.row();
13669                    let positions =
13670                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13671                            px(start)..px(end)
13672                        } else {
13673                            let start_x =
13674                                display_map.x_for_display_point(range.start, &text_layout_details);
13675                            let end_x =
13676                                display_map.x_for_display_point(range.end, &text_layout_details);
13677                            start_x.min(end_x)..start_x.max(end_x)
13678                        };
13679
13680                    let mut maybe_new_selection = None;
13681                    while row != end_row {
13682                        if above {
13683                            row.0 -= 1;
13684                        } else {
13685                            row.0 += 1;
13686                        }
13687                        if let Some(new_selection) = self.selections.build_columnar_selection(
13688                            &display_map,
13689                            row,
13690                            &positions,
13691                            selection.reversed,
13692                            &text_layout_details,
13693                        ) {
13694                            maybe_new_selection = Some(new_selection);
13695                            break;
13696                        }
13697                    }
13698
13699                    if let Some(new_selection) = maybe_new_selection {
13700                        group.stack.push(new_selection.id);
13701                        if above {
13702                            final_selections.push(new_selection);
13703                            final_selections.push(selection);
13704                        } else {
13705                            final_selections.push(selection);
13706                            final_selections.push(new_selection);
13707                        }
13708                    } else {
13709                        final_selections.push(selection);
13710                    }
13711                } else {
13712                    group.stack.pop();
13713                }
13714            } else {
13715                final_selections.push(selection);
13716            }
13717        }
13718
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.select(final_selections);
13721        });
13722
13723        let final_selection_ids: HashSet<_> = self
13724            .selections
13725            .all::<Point>(cx)
13726            .iter()
13727            .map(|s| s.id)
13728            .collect();
13729        state.groups.retain_mut(|group| {
13730            // selections might get merged above so we remove invalid items from stacks
13731            group.stack.retain(|id| final_selection_ids.contains(id));
13732
13733            // single selection in stack can be treated as initial state
13734            group.stack.len() > 1
13735        });
13736
13737        if !state.groups.is_empty() {
13738            self.add_selections_state = Some(state);
13739        }
13740    }
13741
13742    fn select_match_ranges(
13743        &mut self,
13744        range: Range<usize>,
13745        reversed: bool,
13746        replace_newest: bool,
13747        auto_scroll: Option<Autoscroll>,
13748        window: &mut Window,
13749        cx: &mut Context<Editor>,
13750    ) {
13751        self.unfold_ranges(
13752            std::slice::from_ref(&range),
13753            false,
13754            auto_scroll.is_some(),
13755            cx,
13756        );
13757        let effects = if let Some(scroll) = auto_scroll {
13758            SelectionEffects::scroll(scroll)
13759        } else {
13760            SelectionEffects::no_scroll()
13761        };
13762        self.change_selections(effects, window, cx, |s| {
13763            if replace_newest {
13764                s.delete(s.newest_anchor().id);
13765            }
13766            if reversed {
13767                s.insert_range(range.end..range.start);
13768            } else {
13769                s.insert_range(range);
13770            }
13771        });
13772    }
13773
13774    pub fn select_next_match_internal(
13775        &mut self,
13776        display_map: &DisplaySnapshot,
13777        replace_newest: bool,
13778        autoscroll: Option<Autoscroll>,
13779        window: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) -> Result<()> {
13782        let buffer = &display_map.buffer_snapshot;
13783        let mut selections = self.selections.all::<usize>(cx);
13784        if let Some(mut select_next_state) = self.select_next_state.take() {
13785            let query = &select_next_state.query;
13786            if !select_next_state.done {
13787                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13788                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13789                let mut next_selected_range = None;
13790
13791                let bytes_after_last_selection =
13792                    buffer.bytes_in_range(last_selection.end..buffer.len());
13793                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13794                let query_matches = query
13795                    .stream_find_iter(bytes_after_last_selection)
13796                    .map(|result| (last_selection.end, result))
13797                    .chain(
13798                        query
13799                            .stream_find_iter(bytes_before_first_selection)
13800                            .map(|result| (0, result)),
13801                    );
13802
13803                for (start_offset, query_match) in query_matches {
13804                    let query_match = query_match.unwrap(); // can only fail due to I/O
13805                    let offset_range =
13806                        start_offset + query_match.start()..start_offset + query_match.end();
13807
13808                    if !select_next_state.wordwise
13809                        || (!buffer.is_inside_word(offset_range.start, false)
13810                            && !buffer.is_inside_word(offset_range.end, false))
13811                    {
13812                        // TODO: This is n^2, because we might check all the selections
13813                        if !selections
13814                            .iter()
13815                            .any(|selection| selection.range().overlaps(&offset_range))
13816                        {
13817                            next_selected_range = Some(offset_range);
13818                            break;
13819                        }
13820                    }
13821                }
13822
13823                if let Some(next_selected_range) = next_selected_range {
13824                    self.select_match_ranges(
13825                        next_selected_range,
13826                        last_selection.reversed,
13827                        replace_newest,
13828                        autoscroll,
13829                        window,
13830                        cx,
13831                    );
13832                } else {
13833                    select_next_state.done = true;
13834                }
13835            }
13836
13837            self.select_next_state = Some(select_next_state);
13838        } else {
13839            let mut only_carets = true;
13840            let mut same_text_selected = true;
13841            let mut selected_text = None;
13842
13843            let mut selections_iter = selections.iter().peekable();
13844            while let Some(selection) = selections_iter.next() {
13845                if selection.start != selection.end {
13846                    only_carets = false;
13847                }
13848
13849                if same_text_selected {
13850                    if selected_text.is_none() {
13851                        selected_text =
13852                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13853                    }
13854
13855                    if let Some(next_selection) = selections_iter.peek() {
13856                        if next_selection.range().len() == selection.range().len() {
13857                            let next_selected_text = buffer
13858                                .text_for_range(next_selection.range())
13859                                .collect::<String>();
13860                            if Some(next_selected_text) != selected_text {
13861                                same_text_selected = false;
13862                                selected_text = None;
13863                            }
13864                        } else {
13865                            same_text_selected = false;
13866                            selected_text = None;
13867                        }
13868                    }
13869                }
13870            }
13871
13872            if only_carets {
13873                for selection in &mut selections {
13874                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13875                    selection.start = word_range.start;
13876                    selection.end = word_range.end;
13877                    selection.goal = SelectionGoal::None;
13878                    selection.reversed = false;
13879                    self.select_match_ranges(
13880                        selection.start..selection.end,
13881                        selection.reversed,
13882                        replace_newest,
13883                        autoscroll,
13884                        window,
13885                        cx,
13886                    );
13887                }
13888
13889                if selections.len() == 1 {
13890                    let selection = selections
13891                        .last()
13892                        .expect("ensured that there's only one selection");
13893                    let query = buffer
13894                        .text_for_range(selection.start..selection.end)
13895                        .collect::<String>();
13896                    let is_empty = query.is_empty();
13897                    let select_state = SelectNextState {
13898                        query: AhoCorasick::new(&[query])?,
13899                        wordwise: true,
13900                        done: is_empty,
13901                    };
13902                    self.select_next_state = Some(select_state);
13903                } else {
13904                    self.select_next_state = None;
13905                }
13906            } else if let Some(selected_text) = selected_text {
13907                self.select_next_state = Some(SelectNextState {
13908                    query: AhoCorasick::new(&[selected_text])?,
13909                    wordwise: false,
13910                    done: false,
13911                });
13912                self.select_next_match_internal(
13913                    display_map,
13914                    replace_newest,
13915                    autoscroll,
13916                    window,
13917                    cx,
13918                )?;
13919            }
13920        }
13921        Ok(())
13922    }
13923
13924    pub fn select_all_matches(
13925        &mut self,
13926        _action: &SelectAllMatches,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) -> Result<()> {
13930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13931
13932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13933
13934        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13935        let Some(select_next_state) = self.select_next_state.as_mut() else {
13936            return Ok(());
13937        };
13938        if select_next_state.done {
13939            return Ok(());
13940        }
13941
13942        let mut new_selections = Vec::new();
13943
13944        let reversed = self.selections.oldest::<usize>(cx).reversed;
13945        let buffer = &display_map.buffer_snapshot;
13946        let query_matches = select_next_state
13947            .query
13948            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13949
13950        for query_match in query_matches.into_iter() {
13951            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13952            let offset_range = if reversed {
13953                query_match.end()..query_match.start()
13954            } else {
13955                query_match.start()..query_match.end()
13956            };
13957
13958            if !select_next_state.wordwise
13959                || (!buffer.is_inside_word(offset_range.start, false)
13960                    && !buffer.is_inside_word(offset_range.end, false))
13961            {
13962                new_selections.push(offset_range.start..offset_range.end);
13963            }
13964        }
13965
13966        select_next_state.done = true;
13967
13968        if new_selections.is_empty() {
13969            log::error!("bug: new_selections is empty in select_all_matches");
13970            return Ok(());
13971        }
13972
13973        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13974        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13975            selections.select_ranges(new_selections)
13976        });
13977
13978        Ok(())
13979    }
13980
13981    pub fn select_next(
13982        &mut self,
13983        action: &SelectNext,
13984        window: &mut Window,
13985        cx: &mut Context<Self>,
13986    ) -> Result<()> {
13987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13989        self.select_next_match_internal(
13990            &display_map,
13991            action.replace_newest,
13992            Some(Autoscroll::newest()),
13993            window,
13994            cx,
13995        )?;
13996        Ok(())
13997    }
13998
13999    pub fn select_previous(
14000        &mut self,
14001        action: &SelectPrevious,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) -> Result<()> {
14005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14006        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14007        let buffer = &display_map.buffer_snapshot;
14008        let mut selections = self.selections.all::<usize>(cx);
14009        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14010            let query = &select_prev_state.query;
14011            if !select_prev_state.done {
14012                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14013                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14014                let mut next_selected_range = None;
14015                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14016                let bytes_before_last_selection =
14017                    buffer.reversed_bytes_in_range(0..last_selection.start);
14018                let bytes_after_first_selection =
14019                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14020                let query_matches = query
14021                    .stream_find_iter(bytes_before_last_selection)
14022                    .map(|result| (last_selection.start, result))
14023                    .chain(
14024                        query
14025                            .stream_find_iter(bytes_after_first_selection)
14026                            .map(|result| (buffer.len(), result)),
14027                    );
14028                for (end_offset, query_match) in query_matches {
14029                    let query_match = query_match.unwrap(); // can only fail due to I/O
14030                    let offset_range =
14031                        end_offset - query_match.end()..end_offset - query_match.start();
14032
14033                    if !select_prev_state.wordwise
14034                        || (!buffer.is_inside_word(offset_range.start, false)
14035                            && !buffer.is_inside_word(offset_range.end, false))
14036                    {
14037                        next_selected_range = Some(offset_range);
14038                        break;
14039                    }
14040                }
14041
14042                if let Some(next_selected_range) = next_selected_range {
14043                    self.select_match_ranges(
14044                        next_selected_range,
14045                        last_selection.reversed,
14046                        action.replace_newest,
14047                        Some(Autoscroll::newest()),
14048                        window,
14049                        cx,
14050                    );
14051                } else {
14052                    select_prev_state.done = true;
14053                }
14054            }
14055
14056            self.select_prev_state = Some(select_prev_state);
14057        } else {
14058            let mut only_carets = true;
14059            let mut same_text_selected = true;
14060            let mut selected_text = None;
14061
14062            let mut selections_iter = selections.iter().peekable();
14063            while let Some(selection) = selections_iter.next() {
14064                if selection.start != selection.end {
14065                    only_carets = false;
14066                }
14067
14068                if same_text_selected {
14069                    if selected_text.is_none() {
14070                        selected_text =
14071                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14072                    }
14073
14074                    if let Some(next_selection) = selections_iter.peek() {
14075                        if next_selection.range().len() == selection.range().len() {
14076                            let next_selected_text = buffer
14077                                .text_for_range(next_selection.range())
14078                                .collect::<String>();
14079                            if Some(next_selected_text) != selected_text {
14080                                same_text_selected = false;
14081                                selected_text = None;
14082                            }
14083                        } else {
14084                            same_text_selected = false;
14085                            selected_text = None;
14086                        }
14087                    }
14088                }
14089            }
14090
14091            if only_carets {
14092                for selection in &mut selections {
14093                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14094                    selection.start = word_range.start;
14095                    selection.end = word_range.end;
14096                    selection.goal = SelectionGoal::None;
14097                    selection.reversed = false;
14098                    self.select_match_ranges(
14099                        selection.start..selection.end,
14100                        selection.reversed,
14101                        action.replace_newest,
14102                        Some(Autoscroll::newest()),
14103                        window,
14104                        cx,
14105                    );
14106                }
14107                if selections.len() == 1 {
14108                    let selection = selections
14109                        .last()
14110                        .expect("ensured that there's only one selection");
14111                    let query = buffer
14112                        .text_for_range(selection.start..selection.end)
14113                        .collect::<String>();
14114                    let is_empty = query.is_empty();
14115                    let select_state = SelectNextState {
14116                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14117                        wordwise: true,
14118                        done: is_empty,
14119                    };
14120                    self.select_prev_state = Some(select_state);
14121                } else {
14122                    self.select_prev_state = None;
14123                }
14124            } else if let Some(selected_text) = selected_text {
14125                self.select_prev_state = Some(SelectNextState {
14126                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14127                    wordwise: false,
14128                    done: false,
14129                });
14130                self.select_previous(action, window, cx)?;
14131            }
14132        }
14133        Ok(())
14134    }
14135
14136    pub fn find_next_match(
14137        &mut self,
14138        _: &FindNextMatch,
14139        window: &mut Window,
14140        cx: &mut Context<Self>,
14141    ) -> Result<()> {
14142        let selections = self.selections.disjoint_anchors();
14143        match selections.first() {
14144            Some(first) if selections.len() >= 2 => {
14145                self.change_selections(Default::default(), window, cx, |s| {
14146                    s.select_ranges([first.range()]);
14147                });
14148            }
14149            _ => self.select_next(
14150                &SelectNext {
14151                    replace_newest: true,
14152                },
14153                window,
14154                cx,
14155            )?,
14156        }
14157        Ok(())
14158    }
14159
14160    pub fn find_previous_match(
14161        &mut self,
14162        _: &FindPreviousMatch,
14163        window: &mut Window,
14164        cx: &mut Context<Self>,
14165    ) -> Result<()> {
14166        let selections = self.selections.disjoint_anchors();
14167        match selections.last() {
14168            Some(last) if selections.len() >= 2 => {
14169                self.change_selections(Default::default(), window, cx, |s| {
14170                    s.select_ranges([last.range()]);
14171                });
14172            }
14173            _ => self.select_previous(
14174                &SelectPrevious {
14175                    replace_newest: true,
14176                },
14177                window,
14178                cx,
14179            )?,
14180        }
14181        Ok(())
14182    }
14183
14184    pub fn toggle_comments(
14185        &mut self,
14186        action: &ToggleComments,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) {
14190        if self.read_only(cx) {
14191            return;
14192        }
14193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14194        let text_layout_details = &self.text_layout_details(window);
14195        self.transact(window, cx, |this, window, cx| {
14196            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14197            let mut edits = Vec::new();
14198            let mut selection_edit_ranges = Vec::new();
14199            let mut last_toggled_row = None;
14200            let snapshot = this.buffer.read(cx).read(cx);
14201            let empty_str: Arc<str> = Arc::default();
14202            let mut suffixes_inserted = Vec::new();
14203            let ignore_indent = action.ignore_indent;
14204
14205            fn comment_prefix_range(
14206                snapshot: &MultiBufferSnapshot,
14207                row: MultiBufferRow,
14208                comment_prefix: &str,
14209                comment_prefix_whitespace: &str,
14210                ignore_indent: bool,
14211            ) -> Range<Point> {
14212                let indent_size = if ignore_indent {
14213                    0
14214                } else {
14215                    snapshot.indent_size_for_line(row).len
14216                };
14217
14218                let start = Point::new(row.0, indent_size);
14219
14220                let mut line_bytes = snapshot
14221                    .bytes_in_range(start..snapshot.max_point())
14222                    .flatten()
14223                    .copied();
14224
14225                // If this line currently begins with the line comment prefix, then record
14226                // the range containing the prefix.
14227                if line_bytes
14228                    .by_ref()
14229                    .take(comment_prefix.len())
14230                    .eq(comment_prefix.bytes())
14231                {
14232                    // Include any whitespace that matches the comment prefix.
14233                    let matching_whitespace_len = line_bytes
14234                        .zip(comment_prefix_whitespace.bytes())
14235                        .take_while(|(a, b)| a == b)
14236                        .count() as u32;
14237                    let end = Point::new(
14238                        start.row,
14239                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14240                    );
14241                    start..end
14242                } else {
14243                    start..start
14244                }
14245            }
14246
14247            fn comment_suffix_range(
14248                snapshot: &MultiBufferSnapshot,
14249                row: MultiBufferRow,
14250                comment_suffix: &str,
14251                comment_suffix_has_leading_space: bool,
14252            ) -> Range<Point> {
14253                let end = Point::new(row.0, snapshot.line_len(row));
14254                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14255
14256                let mut line_end_bytes = snapshot
14257                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14258                    .flatten()
14259                    .copied();
14260
14261                let leading_space_len = if suffix_start_column > 0
14262                    && line_end_bytes.next() == Some(b' ')
14263                    && comment_suffix_has_leading_space
14264                {
14265                    1
14266                } else {
14267                    0
14268                };
14269
14270                // If this line currently begins with the line comment prefix, then record
14271                // the range containing the prefix.
14272                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14273                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14274                    start..end
14275                } else {
14276                    end..end
14277                }
14278            }
14279
14280            // TODO: Handle selections that cross excerpts
14281            for selection in &mut selections {
14282                let start_column = snapshot
14283                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14284                    .len;
14285                let language = if let Some(language) =
14286                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14287                {
14288                    language
14289                } else {
14290                    continue;
14291                };
14292
14293                selection_edit_ranges.clear();
14294
14295                // If multiple selections contain a given row, avoid processing that
14296                // row more than once.
14297                let mut start_row = MultiBufferRow(selection.start.row);
14298                if last_toggled_row == Some(start_row) {
14299                    start_row = start_row.next_row();
14300                }
14301                let end_row =
14302                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14303                        MultiBufferRow(selection.end.row - 1)
14304                    } else {
14305                        MultiBufferRow(selection.end.row)
14306                    };
14307                last_toggled_row = Some(end_row);
14308
14309                if start_row > end_row {
14310                    continue;
14311                }
14312
14313                // If the language has line comments, toggle those.
14314                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14315
14316                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14317                if ignore_indent {
14318                    full_comment_prefixes = full_comment_prefixes
14319                        .into_iter()
14320                        .map(|s| Arc::from(s.trim_end()))
14321                        .collect();
14322                }
14323
14324                if !full_comment_prefixes.is_empty() {
14325                    let first_prefix = full_comment_prefixes
14326                        .first()
14327                        .expect("prefixes is non-empty");
14328                    let prefix_trimmed_lengths = full_comment_prefixes
14329                        .iter()
14330                        .map(|p| p.trim_end_matches(' ').len())
14331                        .collect::<SmallVec<[usize; 4]>>();
14332
14333                    let mut all_selection_lines_are_comments = true;
14334
14335                    for row in start_row.0..=end_row.0 {
14336                        let row = MultiBufferRow(row);
14337                        if start_row < end_row && snapshot.is_line_blank(row) {
14338                            continue;
14339                        }
14340
14341                        let prefix_range = full_comment_prefixes
14342                            .iter()
14343                            .zip(prefix_trimmed_lengths.iter().copied())
14344                            .map(|(prefix, trimmed_prefix_len)| {
14345                                comment_prefix_range(
14346                                    snapshot.deref(),
14347                                    row,
14348                                    &prefix[..trimmed_prefix_len],
14349                                    &prefix[trimmed_prefix_len..],
14350                                    ignore_indent,
14351                                )
14352                            })
14353                            .max_by_key(|range| range.end.column - range.start.column)
14354                            .expect("prefixes is non-empty");
14355
14356                        if prefix_range.is_empty() {
14357                            all_selection_lines_are_comments = false;
14358                        }
14359
14360                        selection_edit_ranges.push(prefix_range);
14361                    }
14362
14363                    if all_selection_lines_are_comments {
14364                        edits.extend(
14365                            selection_edit_ranges
14366                                .iter()
14367                                .cloned()
14368                                .map(|range| (range, empty_str.clone())),
14369                        );
14370                    } else {
14371                        let min_column = selection_edit_ranges
14372                            .iter()
14373                            .map(|range| range.start.column)
14374                            .min()
14375                            .unwrap_or(0);
14376                        edits.extend(selection_edit_ranges.iter().map(|range| {
14377                            let position = Point::new(range.start.row, min_column);
14378                            (position..position, first_prefix.clone())
14379                        }));
14380                    }
14381                } else if let Some(BlockCommentConfig {
14382                    start: full_comment_prefix,
14383                    end: comment_suffix,
14384                    ..
14385                }) = language.block_comment()
14386                {
14387                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14388                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14389                    let prefix_range = comment_prefix_range(
14390                        snapshot.deref(),
14391                        start_row,
14392                        comment_prefix,
14393                        comment_prefix_whitespace,
14394                        ignore_indent,
14395                    );
14396                    let suffix_range = comment_suffix_range(
14397                        snapshot.deref(),
14398                        end_row,
14399                        comment_suffix.trim_start_matches(' '),
14400                        comment_suffix.starts_with(' '),
14401                    );
14402
14403                    if prefix_range.is_empty() || suffix_range.is_empty() {
14404                        edits.push((
14405                            prefix_range.start..prefix_range.start,
14406                            full_comment_prefix.clone(),
14407                        ));
14408                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14409                        suffixes_inserted.push((end_row, comment_suffix.len()));
14410                    } else {
14411                        edits.push((prefix_range, empty_str.clone()));
14412                        edits.push((suffix_range, empty_str.clone()));
14413                    }
14414                } else {
14415                    continue;
14416                }
14417            }
14418
14419            drop(snapshot);
14420            this.buffer.update(cx, |buffer, cx| {
14421                buffer.edit(edits, None, cx);
14422            });
14423
14424            // Adjust selections so that they end before any comment suffixes that
14425            // were inserted.
14426            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14427            let mut selections = this.selections.all::<Point>(cx);
14428            let snapshot = this.buffer.read(cx).read(cx);
14429            for selection in &mut selections {
14430                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14431                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14432                        Ordering::Less => {
14433                            suffixes_inserted.next();
14434                            continue;
14435                        }
14436                        Ordering::Greater => break,
14437                        Ordering::Equal => {
14438                            if selection.end.column == snapshot.line_len(row) {
14439                                if selection.is_empty() {
14440                                    selection.start.column -= suffix_len as u32;
14441                                }
14442                                selection.end.column -= suffix_len as u32;
14443                            }
14444                            break;
14445                        }
14446                    }
14447                }
14448            }
14449
14450            drop(snapshot);
14451            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14452
14453            let selections = this.selections.all::<Point>(cx);
14454            let selections_on_single_row = selections.windows(2).all(|selections| {
14455                selections[0].start.row == selections[1].start.row
14456                    && selections[0].end.row == selections[1].end.row
14457                    && selections[0].start.row == selections[0].end.row
14458            });
14459            let selections_selecting = selections
14460                .iter()
14461                .any(|selection| selection.start != selection.end);
14462            let advance_downwards = action.advance_downwards
14463                && selections_on_single_row
14464                && !selections_selecting
14465                && !matches!(this.mode, EditorMode::SingleLine { .. });
14466
14467            if advance_downwards {
14468                let snapshot = this.buffer.read(cx).snapshot(cx);
14469
14470                this.change_selections(Default::default(), window, cx, |s| {
14471                    s.move_cursors_with(|display_snapshot, display_point, _| {
14472                        let mut point = display_point.to_point(display_snapshot);
14473                        point.row += 1;
14474                        point = snapshot.clip_point(point, Bias::Left);
14475                        let display_point = point.to_display_point(display_snapshot);
14476                        let goal = SelectionGoal::HorizontalPosition(
14477                            display_snapshot
14478                                .x_for_display_point(display_point, text_layout_details)
14479                                .into(),
14480                        );
14481                        (display_point, goal)
14482                    })
14483                });
14484            }
14485        });
14486    }
14487
14488    pub fn select_enclosing_symbol(
14489        &mut self,
14490        _: &SelectEnclosingSymbol,
14491        window: &mut Window,
14492        cx: &mut Context<Self>,
14493    ) {
14494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14495
14496        let buffer = self.buffer.read(cx).snapshot(cx);
14497        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14498
14499        fn update_selection(
14500            selection: &Selection<usize>,
14501            buffer_snap: &MultiBufferSnapshot,
14502        ) -> Option<Selection<usize>> {
14503            let cursor = selection.head();
14504            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14505            for symbol in symbols.iter().rev() {
14506                let start = symbol.range.start.to_offset(buffer_snap);
14507                let end = symbol.range.end.to_offset(buffer_snap);
14508                let new_range = start..end;
14509                if start < selection.start || end > selection.end {
14510                    return Some(Selection {
14511                        id: selection.id,
14512                        start: new_range.start,
14513                        end: new_range.end,
14514                        goal: SelectionGoal::None,
14515                        reversed: selection.reversed,
14516                    });
14517                }
14518            }
14519            None
14520        }
14521
14522        let mut selected_larger_symbol = false;
14523        let new_selections = old_selections
14524            .iter()
14525            .map(|selection| match update_selection(selection, &buffer) {
14526                Some(new_selection) => {
14527                    if new_selection.range() != selection.range() {
14528                        selected_larger_symbol = true;
14529                    }
14530                    new_selection
14531                }
14532                None => selection.clone(),
14533            })
14534            .collect::<Vec<_>>();
14535
14536        if selected_larger_symbol {
14537            self.change_selections(Default::default(), window, cx, |s| {
14538                s.select(new_selections);
14539            });
14540        }
14541    }
14542
14543    pub fn select_larger_syntax_node(
14544        &mut self,
14545        _: &SelectLargerSyntaxNode,
14546        window: &mut Window,
14547        cx: &mut Context<Self>,
14548    ) {
14549        let Some(visible_row_count) = self.visible_row_count() else {
14550            return;
14551        };
14552        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14553        if old_selections.is_empty() {
14554            return;
14555        }
14556
14557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14558
14559        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14560        let buffer = self.buffer.read(cx).snapshot(cx);
14561
14562        let mut selected_larger_node = false;
14563        let mut new_selections = old_selections
14564            .iter()
14565            .map(|selection| {
14566                let old_range = selection.start..selection.end;
14567
14568                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14569                    // manually select word at selection
14570                    if ["string_content", "inline"].contains(&node.kind()) {
14571                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14572                        // ignore if word is already selected
14573                        if !word_range.is_empty() && old_range != word_range {
14574                            let (last_word_range, _) =
14575                                buffer.surrounding_word(old_range.end, false);
14576                            // only select word if start and end point belongs to same word
14577                            if word_range == last_word_range {
14578                                selected_larger_node = true;
14579                                return Selection {
14580                                    id: selection.id,
14581                                    start: word_range.start,
14582                                    end: word_range.end,
14583                                    goal: SelectionGoal::None,
14584                                    reversed: selection.reversed,
14585                                };
14586                            }
14587                        }
14588                    }
14589                }
14590
14591                let mut new_range = old_range.clone();
14592                while let Some((_node, containing_range)) =
14593                    buffer.syntax_ancestor(new_range.clone())
14594                {
14595                    new_range = match containing_range {
14596                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14597                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14598                    };
14599                    if !display_map.intersects_fold(new_range.start)
14600                        && !display_map.intersects_fold(new_range.end)
14601                    {
14602                        break;
14603                    }
14604                }
14605
14606                selected_larger_node |= new_range != old_range;
14607                Selection {
14608                    id: selection.id,
14609                    start: new_range.start,
14610                    end: new_range.end,
14611                    goal: SelectionGoal::None,
14612                    reversed: selection.reversed,
14613                }
14614            })
14615            .collect::<Vec<_>>();
14616
14617        if !selected_larger_node {
14618            return; // don't put this call in the history
14619        }
14620
14621        // scroll based on transformation done to the last selection created by the user
14622        let (last_old, last_new) = old_selections
14623            .last()
14624            .zip(new_selections.last().cloned())
14625            .expect("old_selections isn't empty");
14626
14627        // revert selection
14628        let is_selection_reversed = {
14629            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14630            new_selections.last_mut().expect("checked above").reversed =
14631                should_newest_selection_be_reversed;
14632            should_newest_selection_be_reversed
14633        };
14634
14635        if selected_larger_node {
14636            self.select_syntax_node_history.disable_clearing = true;
14637            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14638                s.select(new_selections.clone());
14639            });
14640            self.select_syntax_node_history.disable_clearing = false;
14641        }
14642
14643        let start_row = last_new.start.to_display_point(&display_map).row().0;
14644        let end_row = last_new.end.to_display_point(&display_map).row().0;
14645        let selection_height = end_row - start_row + 1;
14646        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14647
14648        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14649        let scroll_behavior = if fits_on_the_screen {
14650            self.request_autoscroll(Autoscroll::fit(), cx);
14651            SelectSyntaxNodeScrollBehavior::FitSelection
14652        } else if is_selection_reversed {
14653            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14654            SelectSyntaxNodeScrollBehavior::CursorTop
14655        } else {
14656            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14657            SelectSyntaxNodeScrollBehavior::CursorBottom
14658        };
14659
14660        self.select_syntax_node_history.push((
14661            old_selections,
14662            scroll_behavior,
14663            is_selection_reversed,
14664        ));
14665    }
14666
14667    pub fn select_smaller_syntax_node(
14668        &mut self,
14669        _: &SelectSmallerSyntaxNode,
14670        window: &mut Window,
14671        cx: &mut Context<Self>,
14672    ) {
14673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14674
14675        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14676            self.select_syntax_node_history.pop()
14677        {
14678            if let Some(selection) = selections.last_mut() {
14679                selection.reversed = is_selection_reversed;
14680            }
14681
14682            self.select_syntax_node_history.disable_clearing = true;
14683            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14684                s.select(selections.to_vec());
14685            });
14686            self.select_syntax_node_history.disable_clearing = false;
14687
14688            match scroll_behavior {
14689                SelectSyntaxNodeScrollBehavior::CursorTop => {
14690                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14691                }
14692                SelectSyntaxNodeScrollBehavior::FitSelection => {
14693                    self.request_autoscroll(Autoscroll::fit(), cx);
14694                }
14695                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14696                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14697                }
14698            }
14699        }
14700    }
14701
14702    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14703        if !EditorSettings::get_global(cx).gutter.runnables {
14704            self.clear_tasks();
14705            return Task::ready(());
14706        }
14707        let project = self.project.as_ref().map(Entity::downgrade);
14708        let task_sources = self.lsp_task_sources(cx);
14709        let multi_buffer = self.buffer.downgrade();
14710        cx.spawn_in(window, async move |editor, cx| {
14711            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14712            let Some(project) = project.and_then(|p| p.upgrade()) else {
14713                return;
14714            };
14715            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14716                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14717            }) else {
14718                return;
14719            };
14720
14721            let hide_runnables = project
14722                .update(cx, |project, cx| {
14723                    // Do not display any test indicators in non-dev server remote projects.
14724                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14725                })
14726                .unwrap_or(true);
14727            if hide_runnables {
14728                return;
14729            }
14730            let new_rows =
14731                cx.background_spawn({
14732                    let snapshot = display_snapshot.clone();
14733                    async move {
14734                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14735                    }
14736                })
14737                    .await;
14738            let Ok(lsp_tasks) =
14739                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14740            else {
14741                return;
14742            };
14743            let lsp_tasks = lsp_tasks.await;
14744
14745            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14746                lsp_tasks
14747                    .into_iter()
14748                    .flat_map(|(kind, tasks)| {
14749                        tasks.into_iter().filter_map(move |(location, task)| {
14750                            Some((kind.clone(), location?, task))
14751                        })
14752                    })
14753                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14754                        let buffer = location.target.buffer;
14755                        let buffer_snapshot = buffer.read(cx).snapshot();
14756                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14757                            |(excerpt_id, snapshot, _)| {
14758                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14759                                    display_snapshot
14760                                        .buffer_snapshot
14761                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14762                                } else {
14763                                    None
14764                                }
14765                            },
14766                        );
14767                        if let Some(offset) = offset {
14768                            let task_buffer_range =
14769                                location.target.range.to_point(&buffer_snapshot);
14770                            let context_buffer_range =
14771                                task_buffer_range.to_offset(&buffer_snapshot);
14772                            let context_range = BufferOffset(context_buffer_range.start)
14773                                ..BufferOffset(context_buffer_range.end);
14774
14775                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14776                                .or_insert_with(|| RunnableTasks {
14777                                    templates: Vec::new(),
14778                                    offset,
14779                                    column: task_buffer_range.start.column,
14780                                    extra_variables: HashMap::default(),
14781                                    context_range,
14782                                })
14783                                .templates
14784                                .push((kind, task.original_task().clone()));
14785                        }
14786
14787                        acc
14788                    })
14789            }) else {
14790                return;
14791            };
14792
14793            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14794                buffer.language_settings(cx).tasks.prefer_lsp
14795            }) else {
14796                return;
14797            };
14798
14799            let rows = Self::runnable_rows(
14800                project,
14801                display_snapshot,
14802                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14803                new_rows,
14804                cx.clone(),
14805            )
14806            .await;
14807            editor
14808                .update(cx, |editor, _| {
14809                    editor.clear_tasks();
14810                    for (key, mut value) in rows {
14811                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14812                            value.templates.extend(lsp_tasks.templates);
14813                        }
14814
14815                        editor.insert_tasks(key, value);
14816                    }
14817                    for (key, value) in lsp_tasks_by_rows {
14818                        editor.insert_tasks(key, value);
14819                    }
14820                })
14821                .ok();
14822        })
14823    }
14824    fn fetch_runnable_ranges(
14825        snapshot: &DisplaySnapshot,
14826        range: Range<Anchor>,
14827    ) -> Vec<language::RunnableRange> {
14828        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14829    }
14830
14831    fn runnable_rows(
14832        project: Entity<Project>,
14833        snapshot: DisplaySnapshot,
14834        prefer_lsp: bool,
14835        runnable_ranges: Vec<RunnableRange>,
14836        cx: AsyncWindowContext,
14837    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14838        cx.spawn(async move |cx| {
14839            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14840            for mut runnable in runnable_ranges {
14841                let Some(tasks) = cx
14842                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14843                    .ok()
14844                else {
14845                    continue;
14846                };
14847                let mut tasks = tasks.await;
14848
14849                if prefer_lsp {
14850                    tasks.retain(|(task_kind, _)| {
14851                        !matches!(task_kind, TaskSourceKind::Language { .. })
14852                    });
14853                }
14854                if tasks.is_empty() {
14855                    continue;
14856                }
14857
14858                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14859                let Some(row) = snapshot
14860                    .buffer_snapshot
14861                    .buffer_line_for_row(MultiBufferRow(point.row))
14862                    .map(|(_, range)| range.start.row)
14863                else {
14864                    continue;
14865                };
14866
14867                let context_range =
14868                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14869                runnable_rows.push((
14870                    (runnable.buffer_id, row),
14871                    RunnableTasks {
14872                        templates: tasks,
14873                        offset: snapshot
14874                            .buffer_snapshot
14875                            .anchor_before(runnable.run_range.start),
14876                        context_range,
14877                        column: point.column,
14878                        extra_variables: runnable.extra_captures,
14879                    },
14880                ));
14881            }
14882            runnable_rows
14883        })
14884    }
14885
14886    fn templates_with_tags(
14887        project: &Entity<Project>,
14888        runnable: &mut Runnable,
14889        cx: &mut App,
14890    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14891        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14892            let (worktree_id, file) = project
14893                .buffer_for_id(runnable.buffer, cx)
14894                .and_then(|buffer| buffer.read(cx).file())
14895                .map(|file| (file.worktree_id(cx), file.clone()))
14896                .unzip();
14897
14898            (
14899                project.task_store().read(cx).task_inventory().cloned(),
14900                worktree_id,
14901                file,
14902            )
14903        });
14904
14905        let tags = mem::take(&mut runnable.tags);
14906        let language = runnable.language.clone();
14907        cx.spawn(async move |cx| {
14908            let mut templates_with_tags = Vec::new();
14909            if let Some(inventory) = inventory {
14910                for RunnableTag(tag) in tags {
14911                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14912                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14913                    }) else {
14914                        return templates_with_tags;
14915                    };
14916                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14917                        move |(_, template)| {
14918                            template.tags.iter().any(|source_tag| source_tag == &tag)
14919                        },
14920                    ));
14921                }
14922            }
14923            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14924
14925            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14926                // Strongest source wins; if we have worktree tag binding, prefer that to
14927                // global and language bindings;
14928                // if we have a global binding, prefer that to language binding.
14929                let first_mismatch = templates_with_tags
14930                    .iter()
14931                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14932                if let Some(index) = first_mismatch {
14933                    templates_with_tags.truncate(index);
14934                }
14935            }
14936
14937            templates_with_tags
14938        })
14939    }
14940
14941    pub fn move_to_enclosing_bracket(
14942        &mut self,
14943        _: &MoveToEnclosingBracket,
14944        window: &mut Window,
14945        cx: &mut Context<Self>,
14946    ) {
14947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14948        self.change_selections(Default::default(), window, cx, |s| {
14949            s.move_offsets_with(|snapshot, selection| {
14950                let Some(enclosing_bracket_ranges) =
14951                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14952                else {
14953                    return;
14954                };
14955
14956                let mut best_length = usize::MAX;
14957                let mut best_inside = false;
14958                let mut best_in_bracket_range = false;
14959                let mut best_destination = None;
14960                for (open, close) in enclosing_bracket_ranges {
14961                    let close = close.to_inclusive();
14962                    let length = close.end() - open.start;
14963                    let inside = selection.start >= open.end && selection.end <= *close.start();
14964                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14965                        || close.contains(&selection.head());
14966
14967                    // If best is next to a bracket and current isn't, skip
14968                    if !in_bracket_range && best_in_bracket_range {
14969                        continue;
14970                    }
14971
14972                    // Prefer smaller lengths unless best is inside and current isn't
14973                    if length > best_length && (best_inside || !inside) {
14974                        continue;
14975                    }
14976
14977                    best_length = length;
14978                    best_inside = inside;
14979                    best_in_bracket_range = in_bracket_range;
14980                    best_destination = Some(
14981                        if close.contains(&selection.start) && close.contains(&selection.end) {
14982                            if inside { open.end } else { open.start }
14983                        } else if inside {
14984                            *close.start()
14985                        } else {
14986                            *close.end()
14987                        },
14988                    );
14989                }
14990
14991                if let Some(destination) = best_destination {
14992                    selection.collapse_to(destination, SelectionGoal::None);
14993                }
14994            })
14995        });
14996    }
14997
14998    pub fn undo_selection(
14999        &mut self,
15000        _: &UndoSelection,
15001        window: &mut Window,
15002        cx: &mut Context<Self>,
15003    ) {
15004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15005        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15006            self.selection_history.mode = SelectionHistoryMode::Undoing;
15007            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15008                this.end_selection(window, cx);
15009                this.change_selections(
15010                    SelectionEffects::scroll(Autoscroll::newest()),
15011                    window,
15012                    cx,
15013                    |s| s.select_anchors(entry.selections.to_vec()),
15014                );
15015            });
15016            self.selection_history.mode = SelectionHistoryMode::Normal;
15017
15018            self.select_next_state = entry.select_next_state;
15019            self.select_prev_state = entry.select_prev_state;
15020            self.add_selections_state = entry.add_selections_state;
15021        }
15022    }
15023
15024    pub fn redo_selection(
15025        &mut self,
15026        _: &RedoSelection,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15032            self.selection_history.mode = SelectionHistoryMode::Redoing;
15033            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15034                this.end_selection(window, cx);
15035                this.change_selections(
15036                    SelectionEffects::scroll(Autoscroll::newest()),
15037                    window,
15038                    cx,
15039                    |s| s.select_anchors(entry.selections.to_vec()),
15040                );
15041            });
15042            self.selection_history.mode = SelectionHistoryMode::Normal;
15043
15044            self.select_next_state = entry.select_next_state;
15045            self.select_prev_state = entry.select_prev_state;
15046            self.add_selections_state = entry.add_selections_state;
15047        }
15048    }
15049
15050    pub fn expand_excerpts(
15051        &mut self,
15052        action: &ExpandExcerpts,
15053        _: &mut Window,
15054        cx: &mut Context<Self>,
15055    ) {
15056        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15057    }
15058
15059    pub fn expand_excerpts_down(
15060        &mut self,
15061        action: &ExpandExcerptsDown,
15062        _: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) {
15065        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15066    }
15067
15068    pub fn expand_excerpts_up(
15069        &mut self,
15070        action: &ExpandExcerptsUp,
15071        _: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15075    }
15076
15077    pub fn expand_excerpts_for_direction(
15078        &mut self,
15079        lines: u32,
15080        direction: ExpandExcerptDirection,
15081
15082        cx: &mut Context<Self>,
15083    ) {
15084        let selections = self.selections.disjoint_anchors();
15085
15086        let lines = if lines == 0 {
15087            EditorSettings::get_global(cx).expand_excerpt_lines
15088        } else {
15089            lines
15090        };
15091
15092        self.buffer.update(cx, |buffer, cx| {
15093            let snapshot = buffer.snapshot(cx);
15094            let mut excerpt_ids = selections
15095                .iter()
15096                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15097                .collect::<Vec<_>>();
15098            excerpt_ids.sort();
15099            excerpt_ids.dedup();
15100            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15101        })
15102    }
15103
15104    pub fn expand_excerpt(
15105        &mut self,
15106        excerpt: ExcerptId,
15107        direction: ExpandExcerptDirection,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) {
15111        let current_scroll_position = self.scroll_position(cx);
15112        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15113        let mut should_scroll_up = false;
15114
15115        if direction == ExpandExcerptDirection::Down {
15116            let multi_buffer = self.buffer.read(cx);
15117            let snapshot = multi_buffer.snapshot(cx);
15118            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15119                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15120                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15121                        let buffer_snapshot = buffer.read(cx).snapshot();
15122                        let excerpt_end_row =
15123                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15124                        let last_row = buffer_snapshot.max_point().row;
15125                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15126                        should_scroll_up = lines_below >= lines_to_expand;
15127                    }
15128                }
15129            }
15130        }
15131
15132        self.buffer.update(cx, |buffer, cx| {
15133            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15134        });
15135
15136        if should_scroll_up {
15137            let new_scroll_position =
15138                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15139            self.set_scroll_position(new_scroll_position, window, cx);
15140        }
15141    }
15142
15143    pub fn go_to_singleton_buffer_point(
15144        &mut self,
15145        point: Point,
15146        window: &mut Window,
15147        cx: &mut Context<Self>,
15148    ) {
15149        self.go_to_singleton_buffer_range(point..point, window, cx);
15150    }
15151
15152    pub fn go_to_singleton_buffer_range(
15153        &mut self,
15154        range: Range<Point>,
15155        window: &mut Window,
15156        cx: &mut Context<Self>,
15157    ) {
15158        let multibuffer = self.buffer().read(cx);
15159        let Some(buffer) = multibuffer.as_singleton() else {
15160            return;
15161        };
15162        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15163            return;
15164        };
15165        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15166            return;
15167        };
15168        self.change_selections(
15169            SelectionEffects::default().nav_history(true),
15170            window,
15171            cx,
15172            |s| s.select_anchor_ranges([start..end]),
15173        );
15174    }
15175
15176    pub fn go_to_diagnostic(
15177        &mut self,
15178        action: &GoToDiagnostic,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) {
15182        if !self.diagnostics_enabled() {
15183            return;
15184        }
15185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15186        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15187    }
15188
15189    pub fn go_to_prev_diagnostic(
15190        &mut self,
15191        action: &GoToPreviousDiagnostic,
15192        window: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) {
15195        if !self.diagnostics_enabled() {
15196            return;
15197        }
15198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15199        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15200    }
15201
15202    pub fn go_to_diagnostic_impl(
15203        &mut self,
15204        direction: Direction,
15205        severity: GoToDiagnosticSeverityFilter,
15206        window: &mut Window,
15207        cx: &mut Context<Self>,
15208    ) {
15209        let buffer = self.buffer.read(cx).snapshot(cx);
15210        let selection = self.selections.newest::<usize>(cx);
15211
15212        let mut active_group_id = None;
15213        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15214            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15215                active_group_id = Some(active_group.group_id);
15216            }
15217        }
15218
15219        fn filtered(
15220            snapshot: EditorSnapshot,
15221            severity: GoToDiagnosticSeverityFilter,
15222            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15223        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15224            diagnostics
15225                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15226                .filter(|entry| entry.range.start != entry.range.end)
15227                .filter(|entry| !entry.diagnostic.is_unnecessary)
15228                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15229        }
15230
15231        let snapshot = self.snapshot(window, cx);
15232        let before = filtered(
15233            snapshot.clone(),
15234            severity,
15235            buffer
15236                .diagnostics_in_range(0..selection.start)
15237                .filter(|entry| entry.range.start <= selection.start),
15238        );
15239        let after = filtered(
15240            snapshot,
15241            severity,
15242            buffer
15243                .diagnostics_in_range(selection.start..buffer.len())
15244                .filter(|entry| entry.range.start >= selection.start),
15245        );
15246
15247        let mut found: Option<DiagnosticEntry<usize>> = None;
15248        if direction == Direction::Prev {
15249            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15250            {
15251                for diagnostic in prev_diagnostics.into_iter().rev() {
15252                    if diagnostic.range.start != selection.start
15253                        || active_group_id
15254                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15255                    {
15256                        found = Some(diagnostic);
15257                        break 'outer;
15258                    }
15259                }
15260            }
15261        } else {
15262            for diagnostic in after.chain(before) {
15263                if diagnostic.range.start != selection.start
15264                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15265                {
15266                    found = Some(diagnostic);
15267                    break;
15268                }
15269            }
15270        }
15271        let Some(next_diagnostic) = found else {
15272            return;
15273        };
15274
15275        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15276            return;
15277        };
15278        self.change_selections(Default::default(), window, cx, |s| {
15279            s.select_ranges(vec![
15280                next_diagnostic.range.start..next_diagnostic.range.start,
15281            ])
15282        });
15283        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15284        self.refresh_inline_completion(false, true, window, cx);
15285    }
15286
15287    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15289        let snapshot = self.snapshot(window, cx);
15290        let selection = self.selections.newest::<Point>(cx);
15291        self.go_to_hunk_before_or_after_position(
15292            &snapshot,
15293            selection.head(),
15294            Direction::Next,
15295            window,
15296            cx,
15297        );
15298    }
15299
15300    pub fn go_to_hunk_before_or_after_position(
15301        &mut self,
15302        snapshot: &EditorSnapshot,
15303        position: Point,
15304        direction: Direction,
15305        window: &mut Window,
15306        cx: &mut Context<Editor>,
15307    ) {
15308        let row = if direction == Direction::Next {
15309            self.hunk_after_position(snapshot, position)
15310                .map(|hunk| hunk.row_range.start)
15311        } else {
15312            self.hunk_before_position(snapshot, position)
15313        };
15314
15315        if let Some(row) = row {
15316            let destination = Point::new(row.0, 0);
15317            let autoscroll = Autoscroll::center();
15318
15319            self.unfold_ranges(&[destination..destination], false, false, cx);
15320            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15321                s.select_ranges([destination..destination]);
15322            });
15323        }
15324    }
15325
15326    fn hunk_after_position(
15327        &mut self,
15328        snapshot: &EditorSnapshot,
15329        position: Point,
15330    ) -> Option<MultiBufferDiffHunk> {
15331        snapshot
15332            .buffer_snapshot
15333            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15334            .find(|hunk| hunk.row_range.start.0 > position.row)
15335            .or_else(|| {
15336                snapshot
15337                    .buffer_snapshot
15338                    .diff_hunks_in_range(Point::zero()..position)
15339                    .find(|hunk| hunk.row_range.end.0 < position.row)
15340            })
15341    }
15342
15343    fn go_to_prev_hunk(
15344        &mut self,
15345        _: &GoToPreviousHunk,
15346        window: &mut Window,
15347        cx: &mut Context<Self>,
15348    ) {
15349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15350        let snapshot = self.snapshot(window, cx);
15351        let selection = self.selections.newest::<Point>(cx);
15352        self.go_to_hunk_before_or_after_position(
15353            &snapshot,
15354            selection.head(),
15355            Direction::Prev,
15356            window,
15357            cx,
15358        );
15359    }
15360
15361    fn hunk_before_position(
15362        &mut self,
15363        snapshot: &EditorSnapshot,
15364        position: Point,
15365    ) -> Option<MultiBufferRow> {
15366        snapshot
15367            .buffer_snapshot
15368            .diff_hunk_before(position)
15369            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15370    }
15371
15372    fn go_to_next_change(
15373        &mut self,
15374        _: &GoToNextChange,
15375        window: &mut Window,
15376        cx: &mut Context<Self>,
15377    ) {
15378        if let Some(selections) = self
15379            .change_list
15380            .next_change(1, Direction::Next)
15381            .map(|s| s.to_vec())
15382        {
15383            self.change_selections(Default::default(), window, cx, |s| {
15384                let map = s.display_map();
15385                s.select_display_ranges(selections.iter().map(|a| {
15386                    let point = a.to_display_point(&map);
15387                    point..point
15388                }))
15389            })
15390        }
15391    }
15392
15393    fn go_to_previous_change(
15394        &mut self,
15395        _: &GoToPreviousChange,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) {
15399        if let Some(selections) = self
15400            .change_list
15401            .next_change(1, Direction::Prev)
15402            .map(|s| s.to_vec())
15403        {
15404            self.change_selections(Default::default(), window, cx, |s| {
15405                let map = s.display_map();
15406                s.select_display_ranges(selections.iter().map(|a| {
15407                    let point = a.to_display_point(&map);
15408                    point..point
15409                }))
15410            })
15411        }
15412    }
15413
15414    fn go_to_line<T: 'static>(
15415        &mut self,
15416        position: Anchor,
15417        highlight_color: Option<Hsla>,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) {
15421        let snapshot = self.snapshot(window, cx).display_snapshot;
15422        let position = position.to_point(&snapshot.buffer_snapshot);
15423        let start = snapshot
15424            .buffer_snapshot
15425            .clip_point(Point::new(position.row, 0), Bias::Left);
15426        let end = start + Point::new(1, 0);
15427        let start = snapshot.buffer_snapshot.anchor_before(start);
15428        let end = snapshot.buffer_snapshot.anchor_before(end);
15429
15430        self.highlight_rows::<T>(
15431            start..end,
15432            highlight_color
15433                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15434            Default::default(),
15435            cx,
15436        );
15437
15438        if self.buffer.read(cx).is_singleton() {
15439            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15440        }
15441    }
15442
15443    pub fn go_to_definition(
15444        &mut self,
15445        _: &GoToDefinition,
15446        window: &mut Window,
15447        cx: &mut Context<Self>,
15448    ) -> Task<Result<Navigated>> {
15449        let definition =
15450            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15451        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15452        cx.spawn_in(window, async move |editor, cx| {
15453            if definition.await? == Navigated::Yes {
15454                return Ok(Navigated::Yes);
15455            }
15456            match fallback_strategy {
15457                GoToDefinitionFallback::None => Ok(Navigated::No),
15458                GoToDefinitionFallback::FindAllReferences => {
15459                    match editor.update_in(cx, |editor, window, cx| {
15460                        editor.find_all_references(&FindAllReferences, window, cx)
15461                    })? {
15462                        Some(references) => references.await,
15463                        None => Ok(Navigated::No),
15464                    }
15465                }
15466            }
15467        })
15468    }
15469
15470    pub fn go_to_declaration(
15471        &mut self,
15472        _: &GoToDeclaration,
15473        window: &mut Window,
15474        cx: &mut Context<Self>,
15475    ) -> Task<Result<Navigated>> {
15476        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15477    }
15478
15479    pub fn go_to_declaration_split(
15480        &mut self,
15481        _: &GoToDeclaration,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) -> Task<Result<Navigated>> {
15485        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15486    }
15487
15488    pub fn go_to_implementation(
15489        &mut self,
15490        _: &GoToImplementation,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) -> Task<Result<Navigated>> {
15494        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15495    }
15496
15497    pub fn go_to_implementation_split(
15498        &mut self,
15499        _: &GoToImplementationSplit,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) -> Task<Result<Navigated>> {
15503        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15504    }
15505
15506    pub fn go_to_type_definition(
15507        &mut self,
15508        _: &GoToTypeDefinition,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) -> Task<Result<Navigated>> {
15512        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15513    }
15514
15515    pub fn go_to_definition_split(
15516        &mut self,
15517        _: &GoToDefinitionSplit,
15518        window: &mut Window,
15519        cx: &mut Context<Self>,
15520    ) -> Task<Result<Navigated>> {
15521        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15522    }
15523
15524    pub fn go_to_type_definition_split(
15525        &mut self,
15526        _: &GoToTypeDefinitionSplit,
15527        window: &mut Window,
15528        cx: &mut Context<Self>,
15529    ) -> Task<Result<Navigated>> {
15530        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15531    }
15532
15533    fn go_to_definition_of_kind(
15534        &mut self,
15535        kind: GotoDefinitionKind,
15536        split: bool,
15537        window: &mut Window,
15538        cx: &mut Context<Self>,
15539    ) -> Task<Result<Navigated>> {
15540        let Some(provider) = self.semantics_provider.clone() else {
15541            return Task::ready(Ok(Navigated::No));
15542        };
15543        let head = self.selections.newest::<usize>(cx).head();
15544        let buffer = self.buffer.read(cx);
15545        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15546            text_anchor
15547        } else {
15548            return Task::ready(Ok(Navigated::No));
15549        };
15550
15551        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15552            return Task::ready(Ok(Navigated::No));
15553        };
15554
15555        cx.spawn_in(window, async move |editor, cx| {
15556            let definitions = definitions.await?;
15557            let navigated = editor
15558                .update_in(cx, |editor, window, cx| {
15559                    editor.navigate_to_hover_links(
15560                        Some(kind),
15561                        definitions
15562                            .into_iter()
15563                            .filter(|location| {
15564                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15565                            })
15566                            .map(HoverLink::Text)
15567                            .collect::<Vec<_>>(),
15568                        split,
15569                        window,
15570                        cx,
15571                    )
15572                })?
15573                .await?;
15574            anyhow::Ok(navigated)
15575        })
15576    }
15577
15578    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15579        let selection = self.selections.newest_anchor();
15580        let head = selection.head();
15581        let tail = selection.tail();
15582
15583        let Some((buffer, start_position)) =
15584            self.buffer.read(cx).text_anchor_for_position(head, cx)
15585        else {
15586            return;
15587        };
15588
15589        let end_position = if head != tail {
15590            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15591                return;
15592            };
15593            Some(pos)
15594        } else {
15595            None
15596        };
15597
15598        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15599            let url = if let Some(end_pos) = end_position {
15600                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15601            } else {
15602                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15603            };
15604
15605            if let Some(url) = url {
15606                editor.update(cx, |_, cx| {
15607                    cx.open_url(&url);
15608                })
15609            } else {
15610                Ok(())
15611            }
15612        });
15613
15614        url_finder.detach();
15615    }
15616
15617    pub fn open_selected_filename(
15618        &mut self,
15619        _: &OpenSelectedFilename,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) {
15623        let Some(workspace) = self.workspace() else {
15624            return;
15625        };
15626
15627        let position = self.selections.newest_anchor().head();
15628
15629        let Some((buffer, buffer_position)) =
15630            self.buffer.read(cx).text_anchor_for_position(position, cx)
15631        else {
15632            return;
15633        };
15634
15635        let project = self.project.clone();
15636
15637        cx.spawn_in(window, async move |_, cx| {
15638            let result = find_file(&buffer, project, buffer_position, cx).await;
15639
15640            if let Some((_, path)) = result {
15641                workspace
15642                    .update_in(cx, |workspace, window, cx| {
15643                        workspace.open_resolved_path(path, window, cx)
15644                    })?
15645                    .await?;
15646            }
15647            anyhow::Ok(())
15648        })
15649        .detach();
15650    }
15651
15652    pub(crate) fn navigate_to_hover_links(
15653        &mut self,
15654        kind: Option<GotoDefinitionKind>,
15655        mut definitions: Vec<HoverLink>,
15656        split: bool,
15657        window: &mut Window,
15658        cx: &mut Context<Editor>,
15659    ) -> Task<Result<Navigated>> {
15660        // If there is one definition, just open it directly
15661        if definitions.len() == 1 {
15662            let definition = definitions.pop().unwrap();
15663
15664            enum TargetTaskResult {
15665                Location(Option<Location>),
15666                AlreadyNavigated,
15667            }
15668
15669            let target_task = match definition {
15670                HoverLink::Text(link) => {
15671                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15672                }
15673                HoverLink::InlayHint(lsp_location, server_id) => {
15674                    let computation =
15675                        self.compute_target_location(lsp_location, server_id, window, cx);
15676                    cx.background_spawn(async move {
15677                        let location = computation.await?;
15678                        Ok(TargetTaskResult::Location(location))
15679                    })
15680                }
15681                HoverLink::Url(url) => {
15682                    cx.open_url(&url);
15683                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15684                }
15685                HoverLink::File(path) => {
15686                    if let Some(workspace) = self.workspace() {
15687                        cx.spawn_in(window, async move |_, cx| {
15688                            workspace
15689                                .update_in(cx, |workspace, window, cx| {
15690                                    workspace.open_resolved_path(path, window, cx)
15691                                })?
15692                                .await
15693                                .map(|_| TargetTaskResult::AlreadyNavigated)
15694                        })
15695                    } else {
15696                        Task::ready(Ok(TargetTaskResult::Location(None)))
15697                    }
15698                }
15699            };
15700            cx.spawn_in(window, async move |editor, cx| {
15701                let target = match target_task.await.context("target resolution task")? {
15702                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15703                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15704                    TargetTaskResult::Location(Some(target)) => target,
15705                };
15706
15707                editor.update_in(cx, |editor, window, cx| {
15708                    let Some(workspace) = editor.workspace() else {
15709                        return Navigated::No;
15710                    };
15711                    let pane = workspace.read(cx).active_pane().clone();
15712
15713                    let range = target.range.to_point(target.buffer.read(cx));
15714                    let range = editor.range_for_match(&range);
15715                    let range = collapse_multiline_range(range);
15716
15717                    if !split
15718                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15719                    {
15720                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15721                    } else {
15722                        window.defer(cx, move |window, cx| {
15723                            let target_editor: Entity<Self> =
15724                                workspace.update(cx, |workspace, cx| {
15725                                    let pane = if split {
15726                                        workspace.adjacent_pane(window, cx)
15727                                    } else {
15728                                        workspace.active_pane().clone()
15729                                    };
15730
15731                                    workspace.open_project_item(
15732                                        pane,
15733                                        target.buffer.clone(),
15734                                        true,
15735                                        true,
15736                                        window,
15737                                        cx,
15738                                    )
15739                                });
15740                            target_editor.update(cx, |target_editor, cx| {
15741                                // When selecting a definition in a different buffer, disable the nav history
15742                                // to avoid creating a history entry at the previous cursor location.
15743                                pane.update(cx, |pane, _| pane.disable_history());
15744                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15745                                pane.update(cx, |pane, _| pane.enable_history());
15746                            });
15747                        });
15748                    }
15749                    Navigated::Yes
15750                })
15751            })
15752        } else if !definitions.is_empty() {
15753            cx.spawn_in(window, async move |editor, cx| {
15754                let (title, location_tasks, workspace) = editor
15755                    .update_in(cx, |editor, window, cx| {
15756                        let tab_kind = match kind {
15757                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15758                            _ => "Definitions",
15759                        };
15760                        let title = definitions
15761                            .iter()
15762                            .find_map(|definition| match definition {
15763                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15764                                    let buffer = origin.buffer.read(cx);
15765                                    format!(
15766                                        "{} for {}",
15767                                        tab_kind,
15768                                        buffer
15769                                            .text_for_range(origin.range.clone())
15770                                            .collect::<String>()
15771                                    )
15772                                }),
15773                                HoverLink::InlayHint(_, _) => None,
15774                                HoverLink::Url(_) => None,
15775                                HoverLink::File(_) => None,
15776                            })
15777                            .unwrap_or(tab_kind.to_string());
15778                        let location_tasks = definitions
15779                            .into_iter()
15780                            .map(|definition| match definition {
15781                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15782                                HoverLink::InlayHint(lsp_location, server_id) => editor
15783                                    .compute_target_location(lsp_location, server_id, window, cx),
15784                                HoverLink::Url(_) => Task::ready(Ok(None)),
15785                                HoverLink::File(_) => Task::ready(Ok(None)),
15786                            })
15787                            .collect::<Vec<_>>();
15788                        (title, location_tasks, editor.workspace().clone())
15789                    })
15790                    .context("location tasks preparation")?;
15791
15792                let locations: Vec<Location> = future::join_all(location_tasks)
15793                    .await
15794                    .into_iter()
15795                    .filter_map(|location| location.transpose())
15796                    .collect::<Result<_>>()
15797                    .context("location tasks")?;
15798
15799                if locations.is_empty() {
15800                    return Ok(Navigated::No);
15801                }
15802
15803                let Some(workspace) = workspace else {
15804                    return Ok(Navigated::No);
15805                };
15806
15807                let opened = workspace
15808                    .update_in(cx, |workspace, window, cx| {
15809                        Self::open_locations_in_multibuffer(
15810                            workspace,
15811                            locations,
15812                            title,
15813                            split,
15814                            MultibufferSelectionMode::First,
15815                            window,
15816                            cx,
15817                        )
15818                    })
15819                    .ok();
15820
15821                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15822            })
15823        } else {
15824            Task::ready(Ok(Navigated::No))
15825        }
15826    }
15827
15828    fn compute_target_location(
15829        &self,
15830        lsp_location: lsp::Location,
15831        server_id: LanguageServerId,
15832        window: &mut Window,
15833        cx: &mut Context<Self>,
15834    ) -> Task<anyhow::Result<Option<Location>>> {
15835        let Some(project) = self.project.clone() else {
15836            return Task::ready(Ok(None));
15837        };
15838
15839        cx.spawn_in(window, async move |editor, cx| {
15840            let location_task = editor.update(cx, |_, cx| {
15841                project.update(cx, |project, cx| {
15842                    let language_server_name = project
15843                        .language_server_statuses(cx)
15844                        .find(|(id, _)| server_id == *id)
15845                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15846                    language_server_name.map(|language_server_name| {
15847                        project.open_local_buffer_via_lsp(
15848                            lsp_location.uri.clone(),
15849                            server_id,
15850                            language_server_name,
15851                            cx,
15852                        )
15853                    })
15854                })
15855            })?;
15856            let location = match location_task {
15857                Some(task) => Some({
15858                    let target_buffer_handle = task.await.context("open local buffer")?;
15859                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15860                        let target_start = target_buffer
15861                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15862                        let target_end = target_buffer
15863                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15864                        target_buffer.anchor_after(target_start)
15865                            ..target_buffer.anchor_before(target_end)
15866                    })?;
15867                    Location {
15868                        buffer: target_buffer_handle,
15869                        range,
15870                    }
15871                }),
15872                None => None,
15873            };
15874            Ok(location)
15875        })
15876    }
15877
15878    pub fn find_all_references(
15879        &mut self,
15880        _: &FindAllReferences,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) -> Option<Task<Result<Navigated>>> {
15884        let selection = self.selections.newest::<usize>(cx);
15885        let multi_buffer = self.buffer.read(cx);
15886        let head = selection.head();
15887
15888        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15889        let head_anchor = multi_buffer_snapshot.anchor_at(
15890            head,
15891            if head < selection.tail() {
15892                Bias::Right
15893            } else {
15894                Bias::Left
15895            },
15896        );
15897
15898        match self
15899            .find_all_references_task_sources
15900            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15901        {
15902            Ok(_) => {
15903                log::info!(
15904                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15905                );
15906                return None;
15907            }
15908            Err(i) => {
15909                self.find_all_references_task_sources.insert(i, head_anchor);
15910            }
15911        }
15912
15913        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15914        let workspace = self.workspace()?;
15915        let project = workspace.read(cx).project().clone();
15916        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15917        Some(cx.spawn_in(window, async move |editor, cx| {
15918            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15919                if let Ok(i) = editor
15920                    .find_all_references_task_sources
15921                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15922                {
15923                    editor.find_all_references_task_sources.remove(i);
15924                }
15925            });
15926
15927            let locations = references.await?;
15928            if locations.is_empty() {
15929                return anyhow::Ok(Navigated::No);
15930            }
15931
15932            workspace.update_in(cx, |workspace, window, cx| {
15933                let title = locations
15934                    .first()
15935                    .as_ref()
15936                    .map(|location| {
15937                        let buffer = location.buffer.read(cx);
15938                        format!(
15939                            "References to `{}`",
15940                            buffer
15941                                .text_for_range(location.range.clone())
15942                                .collect::<String>()
15943                        )
15944                    })
15945                    .unwrap();
15946                Self::open_locations_in_multibuffer(
15947                    workspace,
15948                    locations,
15949                    title,
15950                    false,
15951                    MultibufferSelectionMode::First,
15952                    window,
15953                    cx,
15954                );
15955                Navigated::Yes
15956            })
15957        }))
15958    }
15959
15960    /// Opens a multibuffer with the given project locations in it
15961    pub fn open_locations_in_multibuffer(
15962        workspace: &mut Workspace,
15963        mut locations: Vec<Location>,
15964        title: String,
15965        split: bool,
15966        multibuffer_selection_mode: MultibufferSelectionMode,
15967        window: &mut Window,
15968        cx: &mut Context<Workspace>,
15969    ) {
15970        if locations.is_empty() {
15971            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15972            return;
15973        }
15974
15975        // If there are multiple definitions, open them in a multibuffer
15976        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15977        let mut locations = locations.into_iter().peekable();
15978        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15979        let capability = workspace.project().read(cx).capability();
15980
15981        let excerpt_buffer = cx.new(|cx| {
15982            let mut multibuffer = MultiBuffer::new(capability);
15983            while let Some(location) = locations.next() {
15984                let buffer = location.buffer.read(cx);
15985                let mut ranges_for_buffer = Vec::new();
15986                let range = location.range.to_point(buffer);
15987                ranges_for_buffer.push(range.clone());
15988
15989                while let Some(next_location) = locations.peek() {
15990                    if next_location.buffer == location.buffer {
15991                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15992                        locations.next();
15993                    } else {
15994                        break;
15995                    }
15996                }
15997
15998                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15999                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16000                    PathKey::for_buffer(&location.buffer, cx),
16001                    location.buffer.clone(),
16002                    ranges_for_buffer,
16003                    DEFAULT_MULTIBUFFER_CONTEXT,
16004                    cx,
16005                );
16006                ranges.extend(new_ranges)
16007            }
16008
16009            multibuffer.with_title(title)
16010        });
16011
16012        let editor = cx.new(|cx| {
16013            Editor::for_multibuffer(
16014                excerpt_buffer,
16015                Some(workspace.project().clone()),
16016                window,
16017                cx,
16018            )
16019        });
16020        editor.update(cx, |editor, cx| {
16021            match multibuffer_selection_mode {
16022                MultibufferSelectionMode::First => {
16023                    if let Some(first_range) = ranges.first() {
16024                        editor.change_selections(
16025                            SelectionEffects::no_scroll(),
16026                            window,
16027                            cx,
16028                            |selections| {
16029                                selections.clear_disjoint();
16030                                selections
16031                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16032                            },
16033                        );
16034                    }
16035                    editor.highlight_background::<Self>(
16036                        &ranges,
16037                        |theme| theme.colors().editor_highlighted_line_background,
16038                        cx,
16039                    );
16040                }
16041                MultibufferSelectionMode::All => {
16042                    editor.change_selections(
16043                        SelectionEffects::no_scroll(),
16044                        window,
16045                        cx,
16046                        |selections| {
16047                            selections.clear_disjoint();
16048                            selections.select_anchor_ranges(ranges);
16049                        },
16050                    );
16051                }
16052            }
16053            editor.register_buffers_with_language_servers(cx);
16054        });
16055
16056        let item = Box::new(editor);
16057        let item_id = item.item_id();
16058
16059        if split {
16060            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16061        } else {
16062            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16063                let (preview_item_id, preview_item_idx) =
16064                    workspace.active_pane().read_with(cx, |pane, _| {
16065                        (pane.preview_item_id(), pane.preview_item_idx())
16066                    });
16067
16068                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16069
16070                if let Some(preview_item_id) = preview_item_id {
16071                    workspace.active_pane().update(cx, |pane, cx| {
16072                        pane.remove_item(preview_item_id, false, false, window, cx);
16073                    });
16074                }
16075            } else {
16076                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16077            }
16078        }
16079        workspace.active_pane().update(cx, |pane, cx| {
16080            pane.set_preview_item_id(Some(item_id), cx);
16081        });
16082    }
16083
16084    pub fn rename(
16085        &mut self,
16086        _: &Rename,
16087        window: &mut Window,
16088        cx: &mut Context<Self>,
16089    ) -> Option<Task<Result<()>>> {
16090        use language::ToOffset as _;
16091
16092        let provider = self.semantics_provider.clone()?;
16093        let selection = self.selections.newest_anchor().clone();
16094        let (cursor_buffer, cursor_buffer_position) = self
16095            .buffer
16096            .read(cx)
16097            .text_anchor_for_position(selection.head(), cx)?;
16098        let (tail_buffer, cursor_buffer_position_end) = self
16099            .buffer
16100            .read(cx)
16101            .text_anchor_for_position(selection.tail(), cx)?;
16102        if tail_buffer != cursor_buffer {
16103            return None;
16104        }
16105
16106        let snapshot = cursor_buffer.read(cx).snapshot();
16107        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16108        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16109        let prepare_rename = provider
16110            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16111            .unwrap_or_else(|| Task::ready(Ok(None)));
16112        drop(snapshot);
16113
16114        Some(cx.spawn_in(window, async move |this, cx| {
16115            let rename_range = if let Some(range) = prepare_rename.await? {
16116                Some(range)
16117            } else {
16118                this.update(cx, |this, cx| {
16119                    let buffer = this.buffer.read(cx).snapshot(cx);
16120                    let mut buffer_highlights = this
16121                        .document_highlights_for_position(selection.head(), &buffer)
16122                        .filter(|highlight| {
16123                            highlight.start.excerpt_id == selection.head().excerpt_id
16124                                && highlight.end.excerpt_id == selection.head().excerpt_id
16125                        });
16126                    buffer_highlights
16127                        .next()
16128                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16129                })?
16130            };
16131            if let Some(rename_range) = rename_range {
16132                this.update_in(cx, |this, window, cx| {
16133                    let snapshot = cursor_buffer.read(cx).snapshot();
16134                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16135                    let cursor_offset_in_rename_range =
16136                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16137                    let cursor_offset_in_rename_range_end =
16138                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16139
16140                    this.take_rename(false, window, cx);
16141                    let buffer = this.buffer.read(cx).read(cx);
16142                    let cursor_offset = selection.head().to_offset(&buffer);
16143                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16144                    let rename_end = rename_start + rename_buffer_range.len();
16145                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16146                    let mut old_highlight_id = None;
16147                    let old_name: Arc<str> = buffer
16148                        .chunks(rename_start..rename_end, true)
16149                        .map(|chunk| {
16150                            if old_highlight_id.is_none() {
16151                                old_highlight_id = chunk.syntax_highlight_id;
16152                            }
16153                            chunk.text
16154                        })
16155                        .collect::<String>()
16156                        .into();
16157
16158                    drop(buffer);
16159
16160                    // Position the selection in the rename editor so that it matches the current selection.
16161                    this.show_local_selections = false;
16162                    let rename_editor = cx.new(|cx| {
16163                        let mut editor = Editor::single_line(window, cx);
16164                        editor.buffer.update(cx, |buffer, cx| {
16165                            buffer.edit([(0..0, old_name.clone())], None, cx)
16166                        });
16167                        let rename_selection_range = match cursor_offset_in_rename_range
16168                            .cmp(&cursor_offset_in_rename_range_end)
16169                        {
16170                            Ordering::Equal => {
16171                                editor.select_all(&SelectAll, window, cx);
16172                                return editor;
16173                            }
16174                            Ordering::Less => {
16175                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16176                            }
16177                            Ordering::Greater => {
16178                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16179                            }
16180                        };
16181                        if rename_selection_range.end > old_name.len() {
16182                            editor.select_all(&SelectAll, window, cx);
16183                        } else {
16184                            editor.change_selections(Default::default(), window, cx, |s| {
16185                                s.select_ranges([rename_selection_range]);
16186                            });
16187                        }
16188                        editor
16189                    });
16190                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16191                        if e == &EditorEvent::Focused {
16192                            cx.emit(EditorEvent::FocusedIn)
16193                        }
16194                    })
16195                    .detach();
16196
16197                    let write_highlights =
16198                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16199                    let read_highlights =
16200                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16201                    let ranges = write_highlights
16202                        .iter()
16203                        .flat_map(|(_, ranges)| ranges.iter())
16204                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16205                        .cloned()
16206                        .collect();
16207
16208                    this.highlight_text::<Rename>(
16209                        ranges,
16210                        HighlightStyle {
16211                            fade_out: Some(0.6),
16212                            ..Default::default()
16213                        },
16214                        cx,
16215                    );
16216                    let rename_focus_handle = rename_editor.focus_handle(cx);
16217                    window.focus(&rename_focus_handle);
16218                    let block_id = this.insert_blocks(
16219                        [BlockProperties {
16220                            style: BlockStyle::Flex,
16221                            placement: BlockPlacement::Below(range.start),
16222                            height: Some(1),
16223                            render: Arc::new({
16224                                let rename_editor = rename_editor.clone();
16225                                move |cx: &mut BlockContext| {
16226                                    let mut text_style = cx.editor_style.text.clone();
16227                                    if let Some(highlight_style) = old_highlight_id
16228                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16229                                    {
16230                                        text_style = text_style.highlight(highlight_style);
16231                                    }
16232                                    div()
16233                                        .block_mouse_except_scroll()
16234                                        .pl(cx.anchor_x)
16235                                        .child(EditorElement::new(
16236                                            &rename_editor,
16237                                            EditorStyle {
16238                                                background: cx.theme().system().transparent,
16239                                                local_player: cx.editor_style.local_player,
16240                                                text: text_style,
16241                                                scrollbar_width: cx.editor_style.scrollbar_width,
16242                                                syntax: cx.editor_style.syntax.clone(),
16243                                                status: cx.editor_style.status.clone(),
16244                                                inlay_hints_style: HighlightStyle {
16245                                                    font_weight: Some(FontWeight::BOLD),
16246                                                    ..make_inlay_hints_style(cx.app)
16247                                                },
16248                                                inline_completion_styles: make_suggestion_styles(
16249                                                    cx.app,
16250                                                ),
16251                                                ..EditorStyle::default()
16252                                            },
16253                                        ))
16254                                        .into_any_element()
16255                                }
16256                            }),
16257                            priority: 0,
16258                        }],
16259                        Some(Autoscroll::fit()),
16260                        cx,
16261                    )[0];
16262                    this.pending_rename = Some(RenameState {
16263                        range,
16264                        old_name,
16265                        editor: rename_editor,
16266                        block_id,
16267                    });
16268                })?;
16269            }
16270
16271            Ok(())
16272        }))
16273    }
16274
16275    pub fn confirm_rename(
16276        &mut self,
16277        _: &ConfirmRename,
16278        window: &mut Window,
16279        cx: &mut Context<Self>,
16280    ) -> Option<Task<Result<()>>> {
16281        let rename = self.take_rename(false, window, cx)?;
16282        let workspace = self.workspace()?.downgrade();
16283        let (buffer, start) = self
16284            .buffer
16285            .read(cx)
16286            .text_anchor_for_position(rename.range.start, cx)?;
16287        let (end_buffer, _) = self
16288            .buffer
16289            .read(cx)
16290            .text_anchor_for_position(rename.range.end, cx)?;
16291        if buffer != end_buffer {
16292            return None;
16293        }
16294
16295        let old_name = rename.old_name;
16296        let new_name = rename.editor.read(cx).text(cx);
16297
16298        let rename = self.semantics_provider.as_ref()?.perform_rename(
16299            &buffer,
16300            start,
16301            new_name.clone(),
16302            cx,
16303        )?;
16304
16305        Some(cx.spawn_in(window, async move |editor, cx| {
16306            let project_transaction = rename.await?;
16307            Self::open_project_transaction(
16308                &editor,
16309                workspace,
16310                project_transaction,
16311                format!("Rename: {}{}", old_name, new_name),
16312                cx,
16313            )
16314            .await?;
16315
16316            editor.update(cx, |editor, cx| {
16317                editor.refresh_document_highlights(cx);
16318            })?;
16319            Ok(())
16320        }))
16321    }
16322
16323    fn take_rename(
16324        &mut self,
16325        moving_cursor: bool,
16326        window: &mut Window,
16327        cx: &mut Context<Self>,
16328    ) -> Option<RenameState> {
16329        let rename = self.pending_rename.take()?;
16330        if rename.editor.focus_handle(cx).is_focused(window) {
16331            window.focus(&self.focus_handle);
16332        }
16333
16334        self.remove_blocks(
16335            [rename.block_id].into_iter().collect(),
16336            Some(Autoscroll::fit()),
16337            cx,
16338        );
16339        self.clear_highlights::<Rename>(cx);
16340        self.show_local_selections = true;
16341
16342        if moving_cursor {
16343            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16344                editor.selections.newest::<usize>(cx).head()
16345            });
16346
16347            // Update the selection to match the position of the selection inside
16348            // the rename editor.
16349            let snapshot = self.buffer.read(cx).read(cx);
16350            let rename_range = rename.range.to_offset(&snapshot);
16351            let cursor_in_editor = snapshot
16352                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16353                .min(rename_range.end);
16354            drop(snapshot);
16355
16356            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16357                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16358            });
16359        } else {
16360            self.refresh_document_highlights(cx);
16361        }
16362
16363        Some(rename)
16364    }
16365
16366    pub fn pending_rename(&self) -> Option<&RenameState> {
16367        self.pending_rename.as_ref()
16368    }
16369
16370    fn format(
16371        &mut self,
16372        _: &Format,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) -> Option<Task<Result<()>>> {
16376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16377
16378        let project = match &self.project {
16379            Some(project) => project.clone(),
16380            None => return None,
16381        };
16382
16383        Some(self.perform_format(
16384            project,
16385            FormatTrigger::Manual,
16386            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16387            window,
16388            cx,
16389        ))
16390    }
16391
16392    fn format_selections(
16393        &mut self,
16394        _: &FormatSelections,
16395        window: &mut Window,
16396        cx: &mut Context<Self>,
16397    ) -> Option<Task<Result<()>>> {
16398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16399
16400        let project = match &self.project {
16401            Some(project) => project.clone(),
16402            None => return None,
16403        };
16404
16405        let ranges = self
16406            .selections
16407            .all_adjusted(cx)
16408            .into_iter()
16409            .map(|selection| selection.range())
16410            .collect_vec();
16411
16412        Some(self.perform_format(
16413            project,
16414            FormatTrigger::Manual,
16415            FormatTarget::Ranges(ranges),
16416            window,
16417            cx,
16418        ))
16419    }
16420
16421    fn perform_format(
16422        &mut self,
16423        project: Entity<Project>,
16424        trigger: FormatTrigger,
16425        target: FormatTarget,
16426        window: &mut Window,
16427        cx: &mut Context<Self>,
16428    ) -> Task<Result<()>> {
16429        let buffer = self.buffer.clone();
16430        let (buffers, target) = match target {
16431            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16432            FormatTarget::Ranges(selection_ranges) => {
16433                let multi_buffer = buffer.read(cx);
16434                let snapshot = multi_buffer.read(cx);
16435                let mut buffers = HashSet::default();
16436                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16437                    BTreeMap::new();
16438                for selection_range in selection_ranges {
16439                    for (buffer, buffer_range, _) in
16440                        snapshot.range_to_buffer_ranges(selection_range)
16441                    {
16442                        let buffer_id = buffer.remote_id();
16443                        let start = buffer.anchor_before(buffer_range.start);
16444                        let end = buffer.anchor_after(buffer_range.end);
16445                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16446                        buffer_id_to_ranges
16447                            .entry(buffer_id)
16448                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16449                            .or_insert_with(|| vec![start..end]);
16450                    }
16451                }
16452                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16453            }
16454        };
16455
16456        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16457        let selections_prev = transaction_id_prev
16458            .and_then(|transaction_id_prev| {
16459                // default to selections as they were after the last edit, if we have them,
16460                // instead of how they are now.
16461                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16462                // will take you back to where you made the last edit, instead of staying where you scrolled
16463                self.selection_history
16464                    .transaction(transaction_id_prev)
16465                    .map(|t| t.0.clone())
16466            })
16467            .unwrap_or_else(|| {
16468                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16469                self.selections.disjoint_anchors()
16470            });
16471
16472        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16473        let format = project.update(cx, |project, cx| {
16474            project.format(buffers, target, true, trigger, cx)
16475        });
16476
16477        cx.spawn_in(window, async move |editor, cx| {
16478            let transaction = futures::select_biased! {
16479                transaction = format.log_err().fuse() => transaction,
16480                () = timeout => {
16481                    log::warn!("timed out waiting for formatting");
16482                    None
16483                }
16484            };
16485
16486            buffer
16487                .update(cx, |buffer, cx| {
16488                    if let Some(transaction) = transaction {
16489                        if !buffer.is_singleton() {
16490                            buffer.push_transaction(&transaction.0, cx);
16491                        }
16492                    }
16493                    cx.notify();
16494                })
16495                .ok();
16496
16497            if let Some(transaction_id_now) =
16498                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16499            {
16500                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16501                if has_new_transaction {
16502                    _ = editor.update(cx, |editor, _| {
16503                        editor
16504                            .selection_history
16505                            .insert_transaction(transaction_id_now, selections_prev);
16506                    });
16507                }
16508            }
16509
16510            Ok(())
16511        })
16512    }
16513
16514    fn organize_imports(
16515        &mut self,
16516        _: &OrganizeImports,
16517        window: &mut Window,
16518        cx: &mut Context<Self>,
16519    ) -> Option<Task<Result<()>>> {
16520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16521        let project = match &self.project {
16522            Some(project) => project.clone(),
16523            None => return None,
16524        };
16525        Some(self.perform_code_action_kind(
16526            project,
16527            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16528            window,
16529            cx,
16530        ))
16531    }
16532
16533    fn perform_code_action_kind(
16534        &mut self,
16535        project: Entity<Project>,
16536        kind: CodeActionKind,
16537        window: &mut Window,
16538        cx: &mut Context<Self>,
16539    ) -> Task<Result<()>> {
16540        let buffer = self.buffer.clone();
16541        let buffers = buffer.read(cx).all_buffers();
16542        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16543        let apply_action = project.update(cx, |project, cx| {
16544            project.apply_code_action_kind(buffers, kind, true, cx)
16545        });
16546        cx.spawn_in(window, async move |_, cx| {
16547            let transaction = futures::select_biased! {
16548                () = timeout => {
16549                    log::warn!("timed out waiting for executing code action");
16550                    None
16551                }
16552                transaction = apply_action.log_err().fuse() => transaction,
16553            };
16554            buffer
16555                .update(cx, |buffer, cx| {
16556                    // check if we need this
16557                    if let Some(transaction) = transaction {
16558                        if !buffer.is_singleton() {
16559                            buffer.push_transaction(&transaction.0, cx);
16560                        }
16561                    }
16562                    cx.notify();
16563                })
16564                .ok();
16565            Ok(())
16566        })
16567    }
16568
16569    pub fn restart_language_server(
16570        &mut self,
16571        _: &RestartLanguageServer,
16572        _: &mut Window,
16573        cx: &mut Context<Self>,
16574    ) {
16575        if let Some(project) = self.project.clone() {
16576            self.buffer.update(cx, |multi_buffer, cx| {
16577                project.update(cx, |project, cx| {
16578                    project.restart_language_servers_for_buffers(
16579                        multi_buffer.all_buffers().into_iter().collect(),
16580                        HashSet::default(),
16581                        cx,
16582                    );
16583                });
16584            })
16585        }
16586    }
16587
16588    pub fn stop_language_server(
16589        &mut self,
16590        _: &StopLanguageServer,
16591        _: &mut Window,
16592        cx: &mut Context<Self>,
16593    ) {
16594        if let Some(project) = self.project.clone() {
16595            self.buffer.update(cx, |multi_buffer, cx| {
16596                project.update(cx, |project, cx| {
16597                    project.stop_language_servers_for_buffers(
16598                        multi_buffer.all_buffers().into_iter().collect(),
16599                        HashSet::default(),
16600                        cx,
16601                    );
16602                    cx.emit(project::Event::RefreshInlayHints);
16603                });
16604            });
16605        }
16606    }
16607
16608    fn cancel_language_server_work(
16609        workspace: &mut Workspace,
16610        _: &actions::CancelLanguageServerWork,
16611        _: &mut Window,
16612        cx: &mut Context<Workspace>,
16613    ) {
16614        let project = workspace.project();
16615        let buffers = workspace
16616            .active_item(cx)
16617            .and_then(|item| item.act_as::<Editor>(cx))
16618            .map_or(HashSet::default(), |editor| {
16619                editor.read(cx).buffer.read(cx).all_buffers()
16620            });
16621        project.update(cx, |project, cx| {
16622            project.cancel_language_server_work_for_buffers(buffers, cx);
16623        });
16624    }
16625
16626    fn show_character_palette(
16627        &mut self,
16628        _: &ShowCharacterPalette,
16629        window: &mut Window,
16630        _: &mut Context<Self>,
16631    ) {
16632        window.show_character_palette();
16633    }
16634
16635    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16636        if !self.diagnostics_enabled() {
16637            return;
16638        }
16639
16640        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16641            let buffer = self.buffer.read(cx).snapshot(cx);
16642            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16643            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16644            let is_valid = buffer
16645                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16646                .any(|entry| {
16647                    entry.diagnostic.is_primary
16648                        && !entry.range.is_empty()
16649                        && entry.range.start == primary_range_start
16650                        && entry.diagnostic.message == active_diagnostics.active_message
16651                });
16652
16653            if !is_valid {
16654                self.dismiss_diagnostics(cx);
16655            }
16656        }
16657    }
16658
16659    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16660        match &self.active_diagnostics {
16661            ActiveDiagnostic::Group(group) => Some(group),
16662            _ => None,
16663        }
16664    }
16665
16666    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16667        if !self.diagnostics_enabled() {
16668            return;
16669        }
16670        self.dismiss_diagnostics(cx);
16671        self.active_diagnostics = ActiveDiagnostic::All;
16672    }
16673
16674    fn activate_diagnostics(
16675        &mut self,
16676        buffer_id: BufferId,
16677        diagnostic: DiagnosticEntry<usize>,
16678        window: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) {
16681        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16682            return;
16683        }
16684        self.dismiss_diagnostics(cx);
16685        let snapshot = self.snapshot(window, cx);
16686        let buffer = self.buffer.read(cx).snapshot(cx);
16687        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16688            return;
16689        };
16690
16691        let diagnostic_group = buffer
16692            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16693            .collect::<Vec<_>>();
16694
16695        let blocks =
16696            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16697
16698        let blocks = self.display_map.update(cx, |display_map, cx| {
16699            display_map.insert_blocks(blocks, cx).into_iter().collect()
16700        });
16701        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16702            active_range: buffer.anchor_before(diagnostic.range.start)
16703                ..buffer.anchor_after(diagnostic.range.end),
16704            active_message: diagnostic.diagnostic.message.clone(),
16705            group_id: diagnostic.diagnostic.group_id,
16706            blocks,
16707        });
16708        cx.notify();
16709    }
16710
16711    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16712        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16713            return;
16714        };
16715
16716        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16717        if let ActiveDiagnostic::Group(group) = prev {
16718            self.display_map.update(cx, |display_map, cx| {
16719                display_map.remove_blocks(group.blocks, cx);
16720            });
16721            cx.notify();
16722        }
16723    }
16724
16725    /// Disable inline diagnostics rendering for this editor.
16726    pub fn disable_inline_diagnostics(&mut self) {
16727        self.inline_diagnostics_enabled = false;
16728        self.inline_diagnostics_update = Task::ready(());
16729        self.inline_diagnostics.clear();
16730    }
16731
16732    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16733        self.diagnostics_enabled = false;
16734        self.dismiss_diagnostics(cx);
16735        self.inline_diagnostics_update = Task::ready(());
16736        self.inline_diagnostics.clear();
16737    }
16738
16739    pub fn diagnostics_enabled(&self) -> bool {
16740        self.diagnostics_enabled && self.mode.is_full()
16741    }
16742
16743    pub fn inline_diagnostics_enabled(&self) -> bool {
16744        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16745    }
16746
16747    pub fn show_inline_diagnostics(&self) -> bool {
16748        self.show_inline_diagnostics
16749    }
16750
16751    pub fn toggle_inline_diagnostics(
16752        &mut self,
16753        _: &ToggleInlineDiagnostics,
16754        window: &mut Window,
16755        cx: &mut Context<Editor>,
16756    ) {
16757        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16758        self.refresh_inline_diagnostics(false, window, cx);
16759    }
16760
16761    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16762        self.diagnostics_max_severity = severity;
16763        self.display_map.update(cx, |display_map, _| {
16764            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16765        });
16766    }
16767
16768    pub fn toggle_diagnostics(
16769        &mut self,
16770        _: &ToggleDiagnostics,
16771        window: &mut Window,
16772        cx: &mut Context<Editor>,
16773    ) {
16774        if !self.diagnostics_enabled() {
16775            return;
16776        }
16777
16778        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16779            EditorSettings::get_global(cx)
16780                .diagnostics_max_severity
16781                .filter(|severity| severity != &DiagnosticSeverity::Off)
16782                .unwrap_or(DiagnosticSeverity::Hint)
16783        } else {
16784            DiagnosticSeverity::Off
16785        };
16786        self.set_max_diagnostics_severity(new_severity, cx);
16787        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16788            self.active_diagnostics = ActiveDiagnostic::None;
16789            self.inline_diagnostics_update = Task::ready(());
16790            self.inline_diagnostics.clear();
16791        } else {
16792            self.refresh_inline_diagnostics(false, window, cx);
16793        }
16794
16795        cx.notify();
16796    }
16797
16798    pub fn toggle_minimap(
16799        &mut self,
16800        _: &ToggleMinimap,
16801        window: &mut Window,
16802        cx: &mut Context<Editor>,
16803    ) {
16804        if self.supports_minimap(cx) {
16805            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16806        }
16807    }
16808
16809    fn refresh_inline_diagnostics(
16810        &mut self,
16811        debounce: bool,
16812        window: &mut Window,
16813        cx: &mut Context<Self>,
16814    ) {
16815        let max_severity = ProjectSettings::get_global(cx)
16816            .diagnostics
16817            .inline
16818            .max_severity
16819            .unwrap_or(self.diagnostics_max_severity);
16820
16821        if !self.inline_diagnostics_enabled()
16822            || !self.show_inline_diagnostics
16823            || max_severity == DiagnosticSeverity::Off
16824        {
16825            self.inline_diagnostics_update = Task::ready(());
16826            self.inline_diagnostics.clear();
16827            return;
16828        }
16829
16830        let debounce_ms = ProjectSettings::get_global(cx)
16831            .diagnostics
16832            .inline
16833            .update_debounce_ms;
16834        let debounce = if debounce && debounce_ms > 0 {
16835            Some(Duration::from_millis(debounce_ms))
16836        } else {
16837            None
16838        };
16839        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16840            if let Some(debounce) = debounce {
16841                cx.background_executor().timer(debounce).await;
16842            }
16843            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16844                editor
16845                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16846                    .ok()
16847            }) else {
16848                return;
16849            };
16850
16851            let new_inline_diagnostics = cx
16852                .background_spawn(async move {
16853                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16854                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16855                        let message = diagnostic_entry
16856                            .diagnostic
16857                            .message
16858                            .split_once('\n')
16859                            .map(|(line, _)| line)
16860                            .map(SharedString::new)
16861                            .unwrap_or_else(|| {
16862                                SharedString::from(diagnostic_entry.diagnostic.message)
16863                            });
16864                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16865                        let (Ok(i) | Err(i)) = inline_diagnostics
16866                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16867                        inline_diagnostics.insert(
16868                            i,
16869                            (
16870                                start_anchor,
16871                                InlineDiagnostic {
16872                                    message,
16873                                    group_id: diagnostic_entry.diagnostic.group_id,
16874                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16875                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16876                                    severity: diagnostic_entry.diagnostic.severity,
16877                                },
16878                            ),
16879                        );
16880                    }
16881                    inline_diagnostics
16882                })
16883                .await;
16884
16885            editor
16886                .update(cx, |editor, cx| {
16887                    editor.inline_diagnostics = new_inline_diagnostics;
16888                    cx.notify();
16889                })
16890                .ok();
16891        });
16892    }
16893
16894    fn pull_diagnostics(
16895        &mut self,
16896        buffer_id: Option<BufferId>,
16897        window: &Window,
16898        cx: &mut Context<Self>,
16899    ) -> Option<()> {
16900        if !self.mode().is_full() {
16901            return None;
16902        }
16903        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16904            .diagnostics
16905            .lsp_pull_diagnostics;
16906        if !pull_diagnostics_settings.enabled {
16907            return None;
16908        }
16909        let project = self.project.as_ref()?.downgrade();
16910        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16911        let mut buffers = self.buffer.read(cx).all_buffers();
16912        if let Some(buffer_id) = buffer_id {
16913            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16914        }
16915
16916        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16917            cx.background_executor().timer(debounce).await;
16918
16919            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16920                buffers
16921                    .into_iter()
16922                    .filter_map(|buffer| {
16923                        project
16924                            .update(cx, |project, cx| {
16925                                project.lsp_store().update(cx, |lsp_store, cx| {
16926                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16927                                })
16928                            })
16929                            .ok()
16930                    })
16931                    .collect::<FuturesUnordered<_>>()
16932            }) else {
16933                return;
16934            };
16935
16936            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16937                match pull_task {
16938                    Ok(()) => {
16939                        if editor
16940                            .update_in(cx, |editor, window, cx| {
16941                                editor.update_diagnostics_state(window, cx);
16942                            })
16943                            .is_err()
16944                        {
16945                            return;
16946                        }
16947                    }
16948                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16949                }
16950            }
16951        });
16952
16953        Some(())
16954    }
16955
16956    pub fn set_selections_from_remote(
16957        &mut self,
16958        selections: Vec<Selection<Anchor>>,
16959        pending_selection: Option<Selection<Anchor>>,
16960        window: &mut Window,
16961        cx: &mut Context<Self>,
16962    ) {
16963        let old_cursor_position = self.selections.newest_anchor().head();
16964        self.selections.change_with(cx, |s| {
16965            s.select_anchors(selections);
16966            if let Some(pending_selection) = pending_selection {
16967                s.set_pending(pending_selection, SelectMode::Character);
16968            } else {
16969                s.clear_pending();
16970            }
16971        });
16972        self.selections_did_change(
16973            false,
16974            &old_cursor_position,
16975            SelectionEffects::default(),
16976            window,
16977            cx,
16978        );
16979    }
16980
16981    pub fn transact(
16982        &mut self,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16986    ) -> Option<TransactionId> {
16987        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16988            this.start_transaction_at(Instant::now(), window, cx);
16989            update(this, window, cx);
16990            this.end_transaction_at(Instant::now(), cx)
16991        })
16992    }
16993
16994    pub fn start_transaction_at(
16995        &mut self,
16996        now: Instant,
16997        window: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) {
17000        self.end_selection(window, cx);
17001        if let Some(tx_id) = self
17002            .buffer
17003            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17004        {
17005            self.selection_history
17006                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17007            cx.emit(EditorEvent::TransactionBegun {
17008                transaction_id: tx_id,
17009            })
17010        }
17011    }
17012
17013    pub fn end_transaction_at(
17014        &mut self,
17015        now: Instant,
17016        cx: &mut Context<Self>,
17017    ) -> Option<TransactionId> {
17018        if let Some(transaction_id) = self
17019            .buffer
17020            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17021        {
17022            if let Some((_, end_selections)) =
17023                self.selection_history.transaction_mut(transaction_id)
17024            {
17025                *end_selections = Some(self.selections.disjoint_anchors());
17026            } else {
17027                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17028            }
17029
17030            cx.emit(EditorEvent::Edited { transaction_id });
17031            Some(transaction_id)
17032        } else {
17033            None
17034        }
17035    }
17036
17037    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17038        if self.selection_mark_mode {
17039            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17040                s.move_with(|_, sel| {
17041                    sel.collapse_to(sel.head(), SelectionGoal::None);
17042                });
17043            })
17044        }
17045        self.selection_mark_mode = true;
17046        cx.notify();
17047    }
17048
17049    pub fn swap_selection_ends(
17050        &mut self,
17051        _: &actions::SwapSelectionEnds,
17052        window: &mut Window,
17053        cx: &mut Context<Self>,
17054    ) {
17055        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17056            s.move_with(|_, sel| {
17057                if sel.start != sel.end {
17058                    sel.reversed = !sel.reversed
17059                }
17060            });
17061        });
17062        self.request_autoscroll(Autoscroll::newest(), cx);
17063        cx.notify();
17064    }
17065
17066    pub fn toggle_focus(
17067        workspace: &mut Workspace,
17068        _: &actions::ToggleFocus,
17069        window: &mut Window,
17070        cx: &mut Context<Workspace>,
17071    ) {
17072        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17073            return;
17074        };
17075        workspace.activate_item(&item, true, true, window, cx);
17076    }
17077
17078    pub fn toggle_fold(
17079        &mut self,
17080        _: &actions::ToggleFold,
17081        window: &mut Window,
17082        cx: &mut Context<Self>,
17083    ) {
17084        if self.is_singleton(cx) {
17085            let selection = self.selections.newest::<Point>(cx);
17086
17087            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17088            let range = if selection.is_empty() {
17089                let point = selection.head().to_display_point(&display_map);
17090                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17091                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17092                    .to_point(&display_map);
17093                start..end
17094            } else {
17095                selection.range()
17096            };
17097            if display_map.folds_in_range(range).next().is_some() {
17098                self.unfold_lines(&Default::default(), window, cx)
17099            } else {
17100                self.fold(&Default::default(), window, cx)
17101            }
17102        } else {
17103            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17104            let buffer_ids: HashSet<_> = self
17105                .selections
17106                .disjoint_anchor_ranges()
17107                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17108                .collect();
17109
17110            let should_unfold = buffer_ids
17111                .iter()
17112                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17113
17114            for buffer_id in buffer_ids {
17115                if should_unfold {
17116                    self.unfold_buffer(buffer_id, cx);
17117                } else {
17118                    self.fold_buffer(buffer_id, cx);
17119                }
17120            }
17121        }
17122    }
17123
17124    pub fn toggle_fold_recursive(
17125        &mut self,
17126        _: &actions::ToggleFoldRecursive,
17127        window: &mut Window,
17128        cx: &mut Context<Self>,
17129    ) {
17130        let selection = self.selections.newest::<Point>(cx);
17131
17132        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17133        let range = if selection.is_empty() {
17134            let point = selection.head().to_display_point(&display_map);
17135            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17136            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17137                .to_point(&display_map);
17138            start..end
17139        } else {
17140            selection.range()
17141        };
17142        if display_map.folds_in_range(range).next().is_some() {
17143            self.unfold_recursive(&Default::default(), window, cx)
17144        } else {
17145            self.fold_recursive(&Default::default(), window, cx)
17146        }
17147    }
17148
17149    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17150        if self.is_singleton(cx) {
17151            let mut to_fold = Vec::new();
17152            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17153            let selections = self.selections.all_adjusted(cx);
17154
17155            for selection in selections {
17156                let range = selection.range().sorted();
17157                let buffer_start_row = range.start.row;
17158
17159                if range.start.row != range.end.row {
17160                    let mut found = false;
17161                    let mut row = range.start.row;
17162                    while row <= range.end.row {
17163                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17164                        {
17165                            found = true;
17166                            row = crease.range().end.row + 1;
17167                            to_fold.push(crease);
17168                        } else {
17169                            row += 1
17170                        }
17171                    }
17172                    if found {
17173                        continue;
17174                    }
17175                }
17176
17177                for row in (0..=range.start.row).rev() {
17178                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17179                        if crease.range().end.row >= buffer_start_row {
17180                            to_fold.push(crease);
17181                            if row <= range.start.row {
17182                                break;
17183                            }
17184                        }
17185                    }
17186                }
17187            }
17188
17189            self.fold_creases(to_fold, true, window, cx);
17190        } else {
17191            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17192            let buffer_ids = self
17193                .selections
17194                .disjoint_anchor_ranges()
17195                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17196                .collect::<HashSet<_>>();
17197            for buffer_id in buffer_ids {
17198                self.fold_buffer(buffer_id, cx);
17199            }
17200        }
17201    }
17202
17203    pub fn toggle_fold_all(
17204        &mut self,
17205        _: &actions::ToggleFoldAll,
17206        window: &mut Window,
17207        cx: &mut Context<Self>,
17208    ) {
17209        if self.buffer.read(cx).is_singleton() {
17210            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17211            let has_folds = display_map
17212                .folds_in_range(0..display_map.buffer_snapshot.len())
17213                .next()
17214                .is_some();
17215
17216            if has_folds {
17217                self.unfold_all(&actions::UnfoldAll, window, cx);
17218            } else {
17219                self.fold_all(&actions::FoldAll, window, cx);
17220            }
17221        } else {
17222            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17223            let should_unfold = buffer_ids
17224                .iter()
17225                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17226
17227            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17228                editor
17229                    .update_in(cx, |editor, _, cx| {
17230                        for buffer_id in buffer_ids {
17231                            if should_unfold {
17232                                editor.unfold_buffer(buffer_id, cx);
17233                            } else {
17234                                editor.fold_buffer(buffer_id, cx);
17235                            }
17236                        }
17237                    })
17238                    .ok();
17239            });
17240        }
17241    }
17242
17243    fn fold_at_level(
17244        &mut self,
17245        fold_at: &FoldAtLevel,
17246        window: &mut Window,
17247        cx: &mut Context<Self>,
17248    ) {
17249        if !self.buffer.read(cx).is_singleton() {
17250            return;
17251        }
17252
17253        let fold_at_level = fold_at.0;
17254        let snapshot = self.buffer.read(cx).snapshot(cx);
17255        let mut to_fold = Vec::new();
17256        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17257
17258        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17259            while start_row < end_row {
17260                match self
17261                    .snapshot(window, cx)
17262                    .crease_for_buffer_row(MultiBufferRow(start_row))
17263                {
17264                    Some(crease) => {
17265                        let nested_start_row = crease.range().start.row + 1;
17266                        let nested_end_row = crease.range().end.row;
17267
17268                        if current_level < fold_at_level {
17269                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17270                        } else if current_level == fold_at_level {
17271                            to_fold.push(crease);
17272                        }
17273
17274                        start_row = nested_end_row + 1;
17275                    }
17276                    None => start_row += 1,
17277                }
17278            }
17279        }
17280
17281        self.fold_creases(to_fold, true, window, cx);
17282    }
17283
17284    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17285        if self.buffer.read(cx).is_singleton() {
17286            let mut fold_ranges = Vec::new();
17287            let snapshot = self.buffer.read(cx).snapshot(cx);
17288
17289            for row in 0..snapshot.max_row().0 {
17290                if let Some(foldable_range) = self
17291                    .snapshot(window, cx)
17292                    .crease_for_buffer_row(MultiBufferRow(row))
17293                {
17294                    fold_ranges.push(foldable_range);
17295                }
17296            }
17297
17298            self.fold_creases(fold_ranges, true, window, cx);
17299        } else {
17300            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17301                editor
17302                    .update_in(cx, |editor, _, cx| {
17303                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17304                            editor.fold_buffer(buffer_id, cx);
17305                        }
17306                    })
17307                    .ok();
17308            });
17309        }
17310    }
17311
17312    pub fn fold_function_bodies(
17313        &mut self,
17314        _: &actions::FoldFunctionBodies,
17315        window: &mut Window,
17316        cx: &mut Context<Self>,
17317    ) {
17318        let snapshot = self.buffer.read(cx).snapshot(cx);
17319
17320        let ranges = snapshot
17321            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17322            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17323            .collect::<Vec<_>>();
17324
17325        let creases = ranges
17326            .into_iter()
17327            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17328            .collect();
17329
17330        self.fold_creases(creases, true, window, cx);
17331    }
17332
17333    pub fn fold_recursive(
17334        &mut self,
17335        _: &actions::FoldRecursive,
17336        window: &mut Window,
17337        cx: &mut Context<Self>,
17338    ) {
17339        let mut to_fold = Vec::new();
17340        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17341        let selections = self.selections.all_adjusted(cx);
17342
17343        for selection in selections {
17344            let range = selection.range().sorted();
17345            let buffer_start_row = range.start.row;
17346
17347            if range.start.row != range.end.row {
17348                let mut found = false;
17349                for row in range.start.row..=range.end.row {
17350                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17351                        found = true;
17352                        to_fold.push(crease);
17353                    }
17354                }
17355                if found {
17356                    continue;
17357                }
17358            }
17359
17360            for row in (0..=range.start.row).rev() {
17361                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17362                    if crease.range().end.row >= buffer_start_row {
17363                        to_fold.push(crease);
17364                    } else {
17365                        break;
17366                    }
17367                }
17368            }
17369        }
17370
17371        self.fold_creases(to_fold, true, window, cx);
17372    }
17373
17374    pub fn fold_at(
17375        &mut self,
17376        buffer_row: MultiBufferRow,
17377        window: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) {
17380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17381
17382        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17383            let autoscroll = self
17384                .selections
17385                .all::<Point>(cx)
17386                .iter()
17387                .any(|selection| crease.range().overlaps(&selection.range()));
17388
17389            self.fold_creases(vec![crease], autoscroll, window, cx);
17390        }
17391    }
17392
17393    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17394        if self.is_singleton(cx) {
17395            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17396            let buffer = &display_map.buffer_snapshot;
17397            let selections = self.selections.all::<Point>(cx);
17398            let ranges = selections
17399                .iter()
17400                .map(|s| {
17401                    let range = s.display_range(&display_map).sorted();
17402                    let mut start = range.start.to_point(&display_map);
17403                    let mut end = range.end.to_point(&display_map);
17404                    start.column = 0;
17405                    end.column = buffer.line_len(MultiBufferRow(end.row));
17406                    start..end
17407                })
17408                .collect::<Vec<_>>();
17409
17410            self.unfold_ranges(&ranges, true, true, cx);
17411        } else {
17412            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17413            let buffer_ids = self
17414                .selections
17415                .disjoint_anchor_ranges()
17416                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17417                .collect::<HashSet<_>>();
17418            for buffer_id in buffer_ids {
17419                self.unfold_buffer(buffer_id, cx);
17420            }
17421        }
17422    }
17423
17424    pub fn unfold_recursive(
17425        &mut self,
17426        _: &UnfoldRecursive,
17427        _window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17431        let selections = self.selections.all::<Point>(cx);
17432        let ranges = selections
17433            .iter()
17434            .map(|s| {
17435                let mut range = s.display_range(&display_map).sorted();
17436                *range.start.column_mut() = 0;
17437                *range.end.column_mut() = display_map.line_len(range.end.row());
17438                let start = range.start.to_point(&display_map);
17439                let end = range.end.to_point(&display_map);
17440                start..end
17441            })
17442            .collect::<Vec<_>>();
17443
17444        self.unfold_ranges(&ranges, true, true, cx);
17445    }
17446
17447    pub fn unfold_at(
17448        &mut self,
17449        buffer_row: MultiBufferRow,
17450        _window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) {
17453        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17454
17455        let intersection_range = Point::new(buffer_row.0, 0)
17456            ..Point::new(
17457                buffer_row.0,
17458                display_map.buffer_snapshot.line_len(buffer_row),
17459            );
17460
17461        let autoscroll = self
17462            .selections
17463            .all::<Point>(cx)
17464            .iter()
17465            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17466
17467        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17468    }
17469
17470    pub fn unfold_all(
17471        &mut self,
17472        _: &actions::UnfoldAll,
17473        _window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) {
17476        if self.buffer.read(cx).is_singleton() {
17477            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17478            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17479        } else {
17480            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17481                editor
17482                    .update(cx, |editor, cx| {
17483                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17484                            editor.unfold_buffer(buffer_id, cx);
17485                        }
17486                    })
17487                    .ok();
17488            });
17489        }
17490    }
17491
17492    pub fn fold_selected_ranges(
17493        &mut self,
17494        _: &FoldSelectedRanges,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        let selections = self.selections.all_adjusted(cx);
17499        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17500        let ranges = selections
17501            .into_iter()
17502            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17503            .collect::<Vec<_>>();
17504        self.fold_creases(ranges, true, window, cx);
17505    }
17506
17507    pub fn fold_ranges<T: ToOffset + Clone>(
17508        &mut self,
17509        ranges: Vec<Range<T>>,
17510        auto_scroll: bool,
17511        window: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) {
17514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17515        let ranges = ranges
17516            .into_iter()
17517            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17518            .collect::<Vec<_>>();
17519        self.fold_creases(ranges, auto_scroll, window, cx);
17520    }
17521
17522    pub fn fold_creases<T: ToOffset + Clone>(
17523        &mut self,
17524        creases: Vec<Crease<T>>,
17525        auto_scroll: bool,
17526        _window: &mut Window,
17527        cx: &mut Context<Self>,
17528    ) {
17529        if creases.is_empty() {
17530            return;
17531        }
17532
17533        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17534
17535        if auto_scroll {
17536            self.request_autoscroll(Autoscroll::fit(), cx);
17537        }
17538
17539        cx.notify();
17540
17541        self.scrollbar_marker_state.dirty = true;
17542        self.folds_did_change(cx);
17543    }
17544
17545    /// Removes any folds whose ranges intersect any of the given ranges.
17546    pub fn unfold_ranges<T: ToOffset + Clone>(
17547        &mut self,
17548        ranges: &[Range<T>],
17549        inclusive: bool,
17550        auto_scroll: bool,
17551        cx: &mut Context<Self>,
17552    ) {
17553        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17554            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17555        });
17556        self.folds_did_change(cx);
17557    }
17558
17559    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17560        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17561            return;
17562        }
17563        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17564        self.display_map.update(cx, |display_map, cx| {
17565            display_map.fold_buffers([buffer_id], cx)
17566        });
17567        cx.emit(EditorEvent::BufferFoldToggled {
17568            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17569            folded: true,
17570        });
17571        cx.notify();
17572    }
17573
17574    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17575        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17576            return;
17577        }
17578        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17579        self.display_map.update(cx, |display_map, cx| {
17580            display_map.unfold_buffers([buffer_id], cx);
17581        });
17582        cx.emit(EditorEvent::BufferFoldToggled {
17583            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17584            folded: false,
17585        });
17586        cx.notify();
17587    }
17588
17589    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17590        self.display_map.read(cx).is_buffer_folded(buffer)
17591    }
17592
17593    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17594        self.display_map.read(cx).folded_buffers()
17595    }
17596
17597    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17598        self.display_map.update(cx, |display_map, cx| {
17599            display_map.disable_header_for_buffer(buffer_id, cx);
17600        });
17601        cx.notify();
17602    }
17603
17604    /// Removes any folds with the given ranges.
17605    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17606        &mut self,
17607        ranges: &[Range<T>],
17608        type_id: TypeId,
17609        auto_scroll: bool,
17610        cx: &mut Context<Self>,
17611    ) {
17612        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17613            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17614        });
17615        self.folds_did_change(cx);
17616    }
17617
17618    fn remove_folds_with<T: ToOffset + Clone>(
17619        &mut self,
17620        ranges: &[Range<T>],
17621        auto_scroll: bool,
17622        cx: &mut Context<Self>,
17623        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17624    ) {
17625        if ranges.is_empty() {
17626            return;
17627        }
17628
17629        let mut buffers_affected = HashSet::default();
17630        let multi_buffer = self.buffer().read(cx);
17631        for range in ranges {
17632            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17633                buffers_affected.insert(buffer.read(cx).remote_id());
17634            };
17635        }
17636
17637        self.display_map.update(cx, update);
17638
17639        if auto_scroll {
17640            self.request_autoscroll(Autoscroll::fit(), cx);
17641        }
17642
17643        cx.notify();
17644        self.scrollbar_marker_state.dirty = true;
17645        self.active_indent_guides_state.dirty = true;
17646    }
17647
17648    pub fn update_renderer_widths(
17649        &mut self,
17650        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17651        cx: &mut Context<Self>,
17652    ) -> bool {
17653        self.display_map
17654            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17655    }
17656
17657    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17658        self.display_map.read(cx).fold_placeholder.clone()
17659    }
17660
17661    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17662        self.buffer.update(cx, |buffer, cx| {
17663            buffer.set_all_diff_hunks_expanded(cx);
17664        });
17665    }
17666
17667    pub fn expand_all_diff_hunks(
17668        &mut self,
17669        _: &ExpandAllDiffHunks,
17670        _window: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) {
17673        self.buffer.update(cx, |buffer, cx| {
17674            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17675        });
17676    }
17677
17678    pub fn toggle_selected_diff_hunks(
17679        &mut self,
17680        _: &ToggleSelectedDiffHunks,
17681        _window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) {
17684        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17685        self.toggle_diff_hunks_in_ranges(ranges, cx);
17686    }
17687
17688    pub fn diff_hunks_in_ranges<'a>(
17689        &'a self,
17690        ranges: &'a [Range<Anchor>],
17691        buffer: &'a MultiBufferSnapshot,
17692    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17693        ranges.iter().flat_map(move |range| {
17694            let end_excerpt_id = range.end.excerpt_id;
17695            let range = range.to_point(buffer);
17696            let mut peek_end = range.end;
17697            if range.end.row < buffer.max_row().0 {
17698                peek_end = Point::new(range.end.row + 1, 0);
17699            }
17700            buffer
17701                .diff_hunks_in_range(range.start..peek_end)
17702                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17703        })
17704    }
17705
17706    pub fn has_stageable_diff_hunks_in_ranges(
17707        &self,
17708        ranges: &[Range<Anchor>],
17709        snapshot: &MultiBufferSnapshot,
17710    ) -> bool {
17711        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17712        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17713    }
17714
17715    pub fn toggle_staged_selected_diff_hunks(
17716        &mut self,
17717        _: &::git::ToggleStaged,
17718        _: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) {
17721        let snapshot = self.buffer.read(cx).snapshot(cx);
17722        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17723        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17724        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17725    }
17726
17727    pub fn set_render_diff_hunk_controls(
17728        &mut self,
17729        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17730        cx: &mut Context<Self>,
17731    ) {
17732        self.render_diff_hunk_controls = render_diff_hunk_controls;
17733        cx.notify();
17734    }
17735
17736    pub fn stage_and_next(
17737        &mut self,
17738        _: &::git::StageAndNext,
17739        window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) {
17742        self.do_stage_or_unstage_and_next(true, window, cx);
17743    }
17744
17745    pub fn unstage_and_next(
17746        &mut self,
17747        _: &::git::UnstageAndNext,
17748        window: &mut Window,
17749        cx: &mut Context<Self>,
17750    ) {
17751        self.do_stage_or_unstage_and_next(false, window, cx);
17752    }
17753
17754    pub fn stage_or_unstage_diff_hunks(
17755        &mut self,
17756        stage: bool,
17757        ranges: Vec<Range<Anchor>>,
17758        cx: &mut Context<Self>,
17759    ) {
17760        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17761        cx.spawn(async move |this, cx| {
17762            task.await?;
17763            this.update(cx, |this, cx| {
17764                let snapshot = this.buffer.read(cx).snapshot(cx);
17765                let chunk_by = this
17766                    .diff_hunks_in_ranges(&ranges, &snapshot)
17767                    .chunk_by(|hunk| hunk.buffer_id);
17768                for (buffer_id, hunks) in &chunk_by {
17769                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17770                }
17771            })
17772        })
17773        .detach_and_log_err(cx);
17774    }
17775
17776    fn save_buffers_for_ranges_if_needed(
17777        &mut self,
17778        ranges: &[Range<Anchor>],
17779        cx: &mut Context<Editor>,
17780    ) -> Task<Result<()>> {
17781        let multibuffer = self.buffer.read(cx);
17782        let snapshot = multibuffer.read(cx);
17783        let buffer_ids: HashSet<_> = ranges
17784            .iter()
17785            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17786            .collect();
17787        drop(snapshot);
17788
17789        let mut buffers = HashSet::default();
17790        for buffer_id in buffer_ids {
17791            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17792                let buffer = buffer_entity.read(cx);
17793                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17794                {
17795                    buffers.insert(buffer_entity);
17796                }
17797            }
17798        }
17799
17800        if let Some(project) = &self.project {
17801            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17802        } else {
17803            Task::ready(Ok(()))
17804        }
17805    }
17806
17807    fn do_stage_or_unstage_and_next(
17808        &mut self,
17809        stage: bool,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17814
17815        if ranges.iter().any(|range| range.start != range.end) {
17816            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17817            return;
17818        }
17819
17820        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17821        let snapshot = self.snapshot(window, cx);
17822        let position = self.selections.newest::<Point>(cx).head();
17823        let mut row = snapshot
17824            .buffer_snapshot
17825            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17826            .find(|hunk| hunk.row_range.start.0 > position.row)
17827            .map(|hunk| hunk.row_range.start);
17828
17829        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17830        // Outside of the project diff editor, wrap around to the beginning.
17831        if !all_diff_hunks_expanded {
17832            row = row.or_else(|| {
17833                snapshot
17834                    .buffer_snapshot
17835                    .diff_hunks_in_range(Point::zero()..position)
17836                    .find(|hunk| hunk.row_range.end.0 < position.row)
17837                    .map(|hunk| hunk.row_range.start)
17838            });
17839        }
17840
17841        if let Some(row) = row {
17842            let destination = Point::new(row.0, 0);
17843            let autoscroll = Autoscroll::center();
17844
17845            self.unfold_ranges(&[destination..destination], false, false, cx);
17846            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17847                s.select_ranges([destination..destination]);
17848            });
17849        }
17850    }
17851
17852    fn do_stage_or_unstage(
17853        &self,
17854        stage: bool,
17855        buffer_id: BufferId,
17856        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17857        cx: &mut App,
17858    ) -> Option<()> {
17859        let project = self.project.as_ref()?;
17860        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17861        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17862        let buffer_snapshot = buffer.read(cx).snapshot();
17863        let file_exists = buffer_snapshot
17864            .file()
17865            .is_some_and(|file| file.disk_state().exists());
17866        diff.update(cx, |diff, cx| {
17867            diff.stage_or_unstage_hunks(
17868                stage,
17869                &hunks
17870                    .map(|hunk| buffer_diff::DiffHunk {
17871                        buffer_range: hunk.buffer_range,
17872                        diff_base_byte_range: hunk.diff_base_byte_range,
17873                        secondary_status: hunk.secondary_status,
17874                        range: Point::zero()..Point::zero(), // unused
17875                    })
17876                    .collect::<Vec<_>>(),
17877                &buffer_snapshot,
17878                file_exists,
17879                cx,
17880            )
17881        });
17882        None
17883    }
17884
17885    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17886        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17887        self.buffer
17888            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17889    }
17890
17891    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17892        self.buffer.update(cx, |buffer, cx| {
17893            let ranges = vec![Anchor::min()..Anchor::max()];
17894            if !buffer.all_diff_hunks_expanded()
17895                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17896            {
17897                buffer.collapse_diff_hunks(ranges, cx);
17898                true
17899            } else {
17900                false
17901            }
17902        })
17903    }
17904
17905    fn toggle_diff_hunks_in_ranges(
17906        &mut self,
17907        ranges: Vec<Range<Anchor>>,
17908        cx: &mut Context<Editor>,
17909    ) {
17910        self.buffer.update(cx, |buffer, cx| {
17911            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17912            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17913        })
17914    }
17915
17916    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17917        self.buffer.update(cx, |buffer, cx| {
17918            let snapshot = buffer.snapshot(cx);
17919            let excerpt_id = range.end.excerpt_id;
17920            let point_range = range.to_point(&snapshot);
17921            let expand = !buffer.single_hunk_is_expanded(range, cx);
17922            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17923        })
17924    }
17925
17926    pub(crate) fn apply_all_diff_hunks(
17927        &mut self,
17928        _: &ApplyAllDiffHunks,
17929        window: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) {
17932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17933
17934        let buffers = self.buffer.read(cx).all_buffers();
17935        for branch_buffer in buffers {
17936            branch_buffer.update(cx, |branch_buffer, cx| {
17937                branch_buffer.merge_into_base(Vec::new(), cx);
17938            });
17939        }
17940
17941        if let Some(project) = self.project.clone() {
17942            self.save(
17943                SaveOptions {
17944                    format: true,
17945                    autosave: false,
17946                },
17947                project,
17948                window,
17949                cx,
17950            )
17951            .detach_and_log_err(cx);
17952        }
17953    }
17954
17955    pub(crate) fn apply_selected_diff_hunks(
17956        &mut self,
17957        _: &ApplyDiffHunk,
17958        window: &mut Window,
17959        cx: &mut Context<Self>,
17960    ) {
17961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17962        let snapshot = self.snapshot(window, cx);
17963        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17964        let mut ranges_by_buffer = HashMap::default();
17965        self.transact(window, cx, |editor, _window, cx| {
17966            for hunk in hunks {
17967                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17968                    ranges_by_buffer
17969                        .entry(buffer.clone())
17970                        .or_insert_with(Vec::new)
17971                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17972                }
17973            }
17974
17975            for (buffer, ranges) in ranges_by_buffer {
17976                buffer.update(cx, |buffer, cx| {
17977                    buffer.merge_into_base(ranges, cx);
17978                });
17979            }
17980        });
17981
17982        if let Some(project) = self.project.clone() {
17983            self.save(
17984                SaveOptions {
17985                    format: true,
17986                    autosave: false,
17987                },
17988                project,
17989                window,
17990                cx,
17991            )
17992            .detach_and_log_err(cx);
17993        }
17994    }
17995
17996    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17997        if hovered != self.gutter_hovered {
17998            self.gutter_hovered = hovered;
17999            cx.notify();
18000        }
18001    }
18002
18003    pub fn insert_blocks(
18004        &mut self,
18005        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18006        autoscroll: Option<Autoscroll>,
18007        cx: &mut Context<Self>,
18008    ) -> Vec<CustomBlockId> {
18009        let blocks = self
18010            .display_map
18011            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18012        if let Some(autoscroll) = autoscroll {
18013            self.request_autoscroll(autoscroll, cx);
18014        }
18015        cx.notify();
18016        blocks
18017    }
18018
18019    pub fn resize_blocks(
18020        &mut self,
18021        heights: HashMap<CustomBlockId, u32>,
18022        autoscroll: Option<Autoscroll>,
18023        cx: &mut Context<Self>,
18024    ) {
18025        self.display_map
18026            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18027        if let Some(autoscroll) = autoscroll {
18028            self.request_autoscroll(autoscroll, cx);
18029        }
18030        cx.notify();
18031    }
18032
18033    pub fn replace_blocks(
18034        &mut self,
18035        renderers: HashMap<CustomBlockId, RenderBlock>,
18036        autoscroll: Option<Autoscroll>,
18037        cx: &mut Context<Self>,
18038    ) {
18039        self.display_map
18040            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18041        if let Some(autoscroll) = autoscroll {
18042            self.request_autoscroll(autoscroll, cx);
18043        }
18044        cx.notify();
18045    }
18046
18047    pub fn remove_blocks(
18048        &mut self,
18049        block_ids: HashSet<CustomBlockId>,
18050        autoscroll: Option<Autoscroll>,
18051        cx: &mut Context<Self>,
18052    ) {
18053        self.display_map.update(cx, |display_map, cx| {
18054            display_map.remove_blocks(block_ids, cx)
18055        });
18056        if let Some(autoscroll) = autoscroll {
18057            self.request_autoscroll(autoscroll, cx);
18058        }
18059        cx.notify();
18060    }
18061
18062    pub fn row_for_block(
18063        &self,
18064        block_id: CustomBlockId,
18065        cx: &mut Context<Self>,
18066    ) -> Option<DisplayRow> {
18067        self.display_map
18068            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18069    }
18070
18071    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18072        self.focused_block = Some(focused_block);
18073    }
18074
18075    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18076        self.focused_block.take()
18077    }
18078
18079    pub fn insert_creases(
18080        &mut self,
18081        creases: impl IntoIterator<Item = Crease<Anchor>>,
18082        cx: &mut Context<Self>,
18083    ) -> Vec<CreaseId> {
18084        self.display_map
18085            .update(cx, |map, cx| map.insert_creases(creases, cx))
18086    }
18087
18088    pub fn remove_creases(
18089        &mut self,
18090        ids: impl IntoIterator<Item = CreaseId>,
18091        cx: &mut Context<Self>,
18092    ) -> Vec<(CreaseId, Range<Anchor>)> {
18093        self.display_map
18094            .update(cx, |map, cx| map.remove_creases(ids, cx))
18095    }
18096
18097    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18098        self.display_map
18099            .update(cx, |map, cx| map.snapshot(cx))
18100            .longest_row()
18101    }
18102
18103    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18104        self.display_map
18105            .update(cx, |map, cx| map.snapshot(cx))
18106            .max_point()
18107    }
18108
18109    pub fn text(&self, cx: &App) -> String {
18110        self.buffer.read(cx).read(cx).text()
18111    }
18112
18113    pub fn is_empty(&self, cx: &App) -> bool {
18114        self.buffer.read(cx).read(cx).is_empty()
18115    }
18116
18117    pub fn text_option(&self, cx: &App) -> Option<String> {
18118        let text = self.text(cx);
18119        let text = text.trim();
18120
18121        if text.is_empty() {
18122            return None;
18123        }
18124
18125        Some(text.to_string())
18126    }
18127
18128    pub fn set_text(
18129        &mut self,
18130        text: impl Into<Arc<str>>,
18131        window: &mut Window,
18132        cx: &mut Context<Self>,
18133    ) {
18134        self.transact(window, cx, |this, _, cx| {
18135            this.buffer
18136                .read(cx)
18137                .as_singleton()
18138                .expect("you can only call set_text on editors for singleton buffers")
18139                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18140        });
18141    }
18142
18143    pub fn display_text(&self, cx: &mut App) -> String {
18144        self.display_map
18145            .update(cx, |map, cx| map.snapshot(cx))
18146            .text()
18147    }
18148
18149    fn create_minimap(
18150        &self,
18151        minimap_settings: MinimapSettings,
18152        window: &mut Window,
18153        cx: &mut Context<Self>,
18154    ) -> Option<Entity<Self>> {
18155        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18156            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18157    }
18158
18159    fn initialize_new_minimap(
18160        &self,
18161        minimap_settings: MinimapSettings,
18162        window: &mut Window,
18163        cx: &mut Context<Self>,
18164    ) -> Entity<Self> {
18165        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18166
18167        let mut minimap = Editor::new_internal(
18168            EditorMode::Minimap {
18169                parent: cx.weak_entity(),
18170            },
18171            self.buffer.clone(),
18172            None,
18173            Some(self.display_map.clone()),
18174            window,
18175            cx,
18176        );
18177        minimap.scroll_manager.clone_state(&self.scroll_manager);
18178        minimap.set_text_style_refinement(TextStyleRefinement {
18179            font_size: Some(MINIMAP_FONT_SIZE),
18180            font_weight: Some(MINIMAP_FONT_WEIGHT),
18181            ..Default::default()
18182        });
18183        minimap.update_minimap_configuration(minimap_settings, cx);
18184        cx.new(|_| minimap)
18185    }
18186
18187    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18188        let current_line_highlight = minimap_settings
18189            .current_line_highlight
18190            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18191        self.set_current_line_highlight(Some(current_line_highlight));
18192    }
18193
18194    pub fn minimap(&self) -> Option<&Entity<Self>> {
18195        self.minimap
18196            .as_ref()
18197            .filter(|_| self.minimap_visibility.visible())
18198    }
18199
18200    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18201        let mut wrap_guides = smallvec![];
18202
18203        if self.show_wrap_guides == Some(false) {
18204            return wrap_guides;
18205        }
18206
18207        let settings = self.buffer.read(cx).language_settings(cx);
18208        if settings.show_wrap_guides {
18209            match self.soft_wrap_mode(cx) {
18210                SoftWrap::Column(soft_wrap) => {
18211                    wrap_guides.push((soft_wrap as usize, true));
18212                }
18213                SoftWrap::Bounded(soft_wrap) => {
18214                    wrap_guides.push((soft_wrap as usize, true));
18215                }
18216                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18217            }
18218            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18219        }
18220
18221        wrap_guides
18222    }
18223
18224    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18225        let settings = self.buffer.read(cx).language_settings(cx);
18226        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18227        match mode {
18228            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18229                SoftWrap::None
18230            }
18231            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18232            language_settings::SoftWrap::PreferredLineLength => {
18233                SoftWrap::Column(settings.preferred_line_length)
18234            }
18235            language_settings::SoftWrap::Bounded => {
18236                SoftWrap::Bounded(settings.preferred_line_length)
18237            }
18238        }
18239    }
18240
18241    pub fn set_soft_wrap_mode(
18242        &mut self,
18243        mode: language_settings::SoftWrap,
18244
18245        cx: &mut Context<Self>,
18246    ) {
18247        self.soft_wrap_mode_override = Some(mode);
18248        cx.notify();
18249    }
18250
18251    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18252        self.hard_wrap = hard_wrap;
18253        cx.notify();
18254    }
18255
18256    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18257        self.text_style_refinement = Some(style);
18258    }
18259
18260    /// called by the Element so we know what style we were most recently rendered with.
18261    pub(crate) fn set_style(
18262        &mut self,
18263        style: EditorStyle,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        // We intentionally do not inform the display map about the minimap style
18268        // so that wrapping is not recalculated and stays consistent for the editor
18269        // and its linked minimap.
18270        if !self.mode.is_minimap() {
18271            let rem_size = window.rem_size();
18272            self.display_map.update(cx, |map, cx| {
18273                map.set_font(
18274                    style.text.font(),
18275                    style.text.font_size.to_pixels(rem_size),
18276                    cx,
18277                )
18278            });
18279        }
18280        self.style = Some(style);
18281    }
18282
18283    pub fn style(&self) -> Option<&EditorStyle> {
18284        self.style.as_ref()
18285    }
18286
18287    // Called by the element. This method is not designed to be called outside of the editor
18288    // element's layout code because it does not notify when rewrapping is computed synchronously.
18289    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18290        self.display_map
18291            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18292    }
18293
18294    pub fn set_soft_wrap(&mut self) {
18295        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18296    }
18297
18298    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18299        if self.soft_wrap_mode_override.is_some() {
18300            self.soft_wrap_mode_override.take();
18301        } else {
18302            let soft_wrap = match self.soft_wrap_mode(cx) {
18303                SoftWrap::GitDiff => return,
18304                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18305                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18306                    language_settings::SoftWrap::None
18307                }
18308            };
18309            self.soft_wrap_mode_override = Some(soft_wrap);
18310        }
18311        cx.notify();
18312    }
18313
18314    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18315        let Some(workspace) = self.workspace() else {
18316            return;
18317        };
18318        let fs = workspace.read(cx).app_state().fs.clone();
18319        let current_show = TabBarSettings::get_global(cx).show;
18320        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18321            setting.show = Some(!current_show);
18322        });
18323    }
18324
18325    pub fn toggle_indent_guides(
18326        &mut self,
18327        _: &ToggleIndentGuides,
18328        _: &mut Window,
18329        cx: &mut Context<Self>,
18330    ) {
18331        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18332            self.buffer
18333                .read(cx)
18334                .language_settings(cx)
18335                .indent_guides
18336                .enabled
18337        });
18338        self.show_indent_guides = Some(!currently_enabled);
18339        cx.notify();
18340    }
18341
18342    fn should_show_indent_guides(&self) -> Option<bool> {
18343        self.show_indent_guides
18344    }
18345
18346    pub fn toggle_line_numbers(
18347        &mut self,
18348        _: &ToggleLineNumbers,
18349        _: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        let mut editor_settings = EditorSettings::get_global(cx).clone();
18353        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18354        EditorSettings::override_global(editor_settings, cx);
18355    }
18356
18357    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18358        if let Some(show_line_numbers) = self.show_line_numbers {
18359            return show_line_numbers;
18360        }
18361        EditorSettings::get_global(cx).gutter.line_numbers
18362    }
18363
18364    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18365        self.use_relative_line_numbers
18366            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18367    }
18368
18369    pub fn toggle_relative_line_numbers(
18370        &mut self,
18371        _: &ToggleRelativeLineNumbers,
18372        _: &mut Window,
18373        cx: &mut Context<Self>,
18374    ) {
18375        let is_relative = self.should_use_relative_line_numbers(cx);
18376        self.set_relative_line_number(Some(!is_relative), cx)
18377    }
18378
18379    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18380        self.use_relative_line_numbers = is_relative;
18381        cx.notify();
18382    }
18383
18384    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18385        self.show_gutter = show_gutter;
18386        cx.notify();
18387    }
18388
18389    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18390        self.show_scrollbars = ScrollbarAxes {
18391            horizontal: show,
18392            vertical: show,
18393        };
18394        cx.notify();
18395    }
18396
18397    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18398        self.show_scrollbars.vertical = show;
18399        cx.notify();
18400    }
18401
18402    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18403        self.show_scrollbars.horizontal = show;
18404        cx.notify();
18405    }
18406
18407    pub fn set_minimap_visibility(
18408        &mut self,
18409        minimap_visibility: MinimapVisibility,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) {
18413        if self.minimap_visibility != minimap_visibility {
18414            if minimap_visibility.visible() && self.minimap.is_none() {
18415                let minimap_settings = EditorSettings::get_global(cx).minimap;
18416                self.minimap =
18417                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18418            }
18419            self.minimap_visibility = minimap_visibility;
18420            cx.notify();
18421        }
18422    }
18423
18424    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18425        self.set_show_scrollbars(false, cx);
18426        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18427    }
18428
18429    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18430        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18431    }
18432
18433    /// Normally the text in full mode and auto height editors is padded on the
18434    /// left side by roughly half a character width for improved hit testing.
18435    ///
18436    /// Use this method to disable this for cases where this is not wanted (e.g.
18437    /// if you want to align the editor text with some other text above or below)
18438    /// or if you want to add this padding to single-line editors.
18439    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18440        self.offset_content = offset_content;
18441        cx.notify();
18442    }
18443
18444    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18445        self.show_line_numbers = Some(show_line_numbers);
18446        cx.notify();
18447    }
18448
18449    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18450        self.disable_expand_excerpt_buttons = true;
18451        cx.notify();
18452    }
18453
18454    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18455        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18456        cx.notify();
18457    }
18458
18459    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18460        self.show_code_actions = Some(show_code_actions);
18461        cx.notify();
18462    }
18463
18464    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18465        self.show_runnables = Some(show_runnables);
18466        cx.notify();
18467    }
18468
18469    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18470        self.show_breakpoints = Some(show_breakpoints);
18471        cx.notify();
18472    }
18473
18474    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18475        if self.display_map.read(cx).masked != masked {
18476            self.display_map.update(cx, |map, _| map.masked = masked);
18477        }
18478        cx.notify()
18479    }
18480
18481    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18482        self.show_wrap_guides = Some(show_wrap_guides);
18483        cx.notify();
18484    }
18485
18486    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18487        self.show_indent_guides = Some(show_indent_guides);
18488        cx.notify();
18489    }
18490
18491    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18492        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18493            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18494                if let Some(dir) = file.abs_path(cx).parent() {
18495                    return Some(dir.to_owned());
18496                }
18497            }
18498
18499            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18500                return Some(project_path.path.to_path_buf());
18501            }
18502        }
18503
18504        None
18505    }
18506
18507    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18508        self.active_excerpt(cx)?
18509            .1
18510            .read(cx)
18511            .file()
18512            .and_then(|f| f.as_local())
18513    }
18514
18515    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18516        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18517            let buffer = buffer.read(cx);
18518            if let Some(project_path) = buffer.project_path(cx) {
18519                let project = self.project.as_ref()?.read(cx);
18520                project.absolute_path(&project_path, cx)
18521            } else {
18522                buffer
18523                    .file()
18524                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18525            }
18526        })
18527    }
18528
18529    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18530        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18531            let project_path = buffer.read(cx).project_path(cx)?;
18532            let project = self.project.as_ref()?.read(cx);
18533            let entry = project.entry_for_path(&project_path, cx)?;
18534            let path = entry.path.to_path_buf();
18535            Some(path)
18536        })
18537    }
18538
18539    pub fn reveal_in_finder(
18540        &mut self,
18541        _: &RevealInFileManager,
18542        _window: &mut Window,
18543        cx: &mut Context<Self>,
18544    ) {
18545        if let Some(target) = self.target_file(cx) {
18546            cx.reveal_path(&target.abs_path(cx));
18547        }
18548    }
18549
18550    pub fn copy_path(
18551        &mut self,
18552        _: &zed_actions::workspace::CopyPath,
18553        _window: &mut Window,
18554        cx: &mut Context<Self>,
18555    ) {
18556        if let Some(path) = self.target_file_abs_path(cx) {
18557            if let Some(path) = path.to_str() {
18558                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18559            }
18560        }
18561    }
18562
18563    pub fn copy_relative_path(
18564        &mut self,
18565        _: &zed_actions::workspace::CopyRelativePath,
18566        _window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        if let Some(path) = self.target_file_path(cx) {
18570            if let Some(path) = path.to_str() {
18571                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18572            }
18573        }
18574    }
18575
18576    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18577        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18578            buffer.read(cx).project_path(cx)
18579        } else {
18580            None
18581        }
18582    }
18583
18584    // Returns true if the editor handled a go-to-line request
18585    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18586        maybe!({
18587            let breakpoint_store = self.breakpoint_store.as_ref()?;
18588
18589            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18590            else {
18591                self.clear_row_highlights::<ActiveDebugLine>();
18592                return None;
18593            };
18594
18595            let position = active_stack_frame.position;
18596            let buffer_id = position.buffer_id?;
18597            let snapshot = self
18598                .project
18599                .as_ref()?
18600                .read(cx)
18601                .buffer_for_id(buffer_id, cx)?
18602                .read(cx)
18603                .snapshot();
18604
18605            let mut handled = false;
18606            for (id, ExcerptRange { context, .. }) in
18607                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18608            {
18609                if context.start.cmp(&position, &snapshot).is_ge()
18610                    || context.end.cmp(&position, &snapshot).is_lt()
18611                {
18612                    continue;
18613                }
18614                let snapshot = self.buffer.read(cx).snapshot(cx);
18615                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18616
18617                handled = true;
18618                self.clear_row_highlights::<ActiveDebugLine>();
18619
18620                self.go_to_line::<ActiveDebugLine>(
18621                    multibuffer_anchor,
18622                    Some(cx.theme().colors().editor_debugger_active_line_background),
18623                    window,
18624                    cx,
18625                );
18626
18627                cx.notify();
18628            }
18629
18630            handled.then_some(())
18631        })
18632        .is_some()
18633    }
18634
18635    pub fn copy_file_name_without_extension(
18636        &mut self,
18637        _: &CopyFileNameWithoutExtension,
18638        _: &mut Window,
18639        cx: &mut Context<Self>,
18640    ) {
18641        if let Some(file) = self.target_file(cx) {
18642            if let Some(file_stem) = file.path().file_stem() {
18643                if let Some(name) = file_stem.to_str() {
18644                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18645                }
18646            }
18647        }
18648    }
18649
18650    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18651        if let Some(file) = self.target_file(cx) {
18652            if let Some(file_name) = file.path().file_name() {
18653                if let Some(name) = file_name.to_str() {
18654                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18655                }
18656            }
18657        }
18658    }
18659
18660    pub fn toggle_git_blame(
18661        &mut self,
18662        _: &::git::Blame,
18663        window: &mut Window,
18664        cx: &mut Context<Self>,
18665    ) {
18666        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18667
18668        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18669            self.start_git_blame(true, window, cx);
18670        }
18671
18672        cx.notify();
18673    }
18674
18675    pub fn toggle_git_blame_inline(
18676        &mut self,
18677        _: &ToggleGitBlameInline,
18678        window: &mut Window,
18679        cx: &mut Context<Self>,
18680    ) {
18681        self.toggle_git_blame_inline_internal(true, window, cx);
18682        cx.notify();
18683    }
18684
18685    pub fn open_git_blame_commit(
18686        &mut self,
18687        _: &OpenGitBlameCommit,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        self.open_git_blame_commit_internal(window, cx);
18692    }
18693
18694    fn open_git_blame_commit_internal(
18695        &mut self,
18696        window: &mut Window,
18697        cx: &mut Context<Self>,
18698    ) -> Option<()> {
18699        let blame = self.blame.as_ref()?;
18700        let snapshot = self.snapshot(window, cx);
18701        let cursor = self.selections.newest::<Point>(cx).head();
18702        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18703        let blame_entry = blame
18704            .update(cx, |blame, cx| {
18705                blame
18706                    .blame_for_rows(
18707                        &[RowInfo {
18708                            buffer_id: Some(buffer.remote_id()),
18709                            buffer_row: Some(point.row),
18710                            ..Default::default()
18711                        }],
18712                        cx,
18713                    )
18714                    .next()
18715            })
18716            .flatten()?;
18717        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18718        let repo = blame.read(cx).repository(cx)?;
18719        let workspace = self.workspace()?.downgrade();
18720        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18721        None
18722    }
18723
18724    pub fn git_blame_inline_enabled(&self) -> bool {
18725        self.git_blame_inline_enabled
18726    }
18727
18728    pub fn toggle_selection_menu(
18729        &mut self,
18730        _: &ToggleSelectionMenu,
18731        _: &mut Window,
18732        cx: &mut Context<Self>,
18733    ) {
18734        self.show_selection_menu = self
18735            .show_selection_menu
18736            .map(|show_selections_menu| !show_selections_menu)
18737            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18738
18739        cx.notify();
18740    }
18741
18742    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18743        self.show_selection_menu
18744            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18745    }
18746
18747    fn start_git_blame(
18748        &mut self,
18749        user_triggered: bool,
18750        window: &mut Window,
18751        cx: &mut Context<Self>,
18752    ) {
18753        if let Some(project) = self.project.as_ref() {
18754            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18755                return;
18756            };
18757
18758            if buffer.read(cx).file().is_none() {
18759                return;
18760            }
18761
18762            let focused = self.focus_handle(cx).contains_focused(window, cx);
18763
18764            let project = project.clone();
18765            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18766            self.blame_subscription =
18767                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18768            self.blame = Some(blame);
18769        }
18770    }
18771
18772    fn toggle_git_blame_inline_internal(
18773        &mut self,
18774        user_triggered: bool,
18775        window: &mut Window,
18776        cx: &mut Context<Self>,
18777    ) {
18778        if self.git_blame_inline_enabled {
18779            self.git_blame_inline_enabled = false;
18780            self.show_git_blame_inline = false;
18781            self.show_git_blame_inline_delay_task.take();
18782        } else {
18783            self.git_blame_inline_enabled = true;
18784            self.start_git_blame_inline(user_triggered, window, cx);
18785        }
18786
18787        cx.notify();
18788    }
18789
18790    fn start_git_blame_inline(
18791        &mut self,
18792        user_triggered: bool,
18793        window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        self.start_git_blame(user_triggered, window, cx);
18797
18798        if ProjectSettings::get_global(cx)
18799            .git
18800            .inline_blame_delay()
18801            .is_some()
18802        {
18803            self.start_inline_blame_timer(window, cx);
18804        } else {
18805            self.show_git_blame_inline = true
18806        }
18807    }
18808
18809    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18810        self.blame.as_ref()
18811    }
18812
18813    pub fn show_git_blame_gutter(&self) -> bool {
18814        self.show_git_blame_gutter
18815    }
18816
18817    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18818        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18819    }
18820
18821    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18822        self.show_git_blame_inline
18823            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18824            && !self.newest_selection_head_on_empty_line(cx)
18825            && self.has_blame_entries(cx)
18826    }
18827
18828    fn has_blame_entries(&self, cx: &App) -> bool {
18829        self.blame()
18830            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18831    }
18832
18833    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18834        let cursor_anchor = self.selections.newest_anchor().head();
18835
18836        let snapshot = self.buffer.read(cx).snapshot(cx);
18837        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18838
18839        snapshot.line_len(buffer_row) == 0
18840    }
18841
18842    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18843        let buffer_and_selection = maybe!({
18844            let selection = self.selections.newest::<Point>(cx);
18845            let selection_range = selection.range();
18846
18847            let multi_buffer = self.buffer().read(cx);
18848            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18849            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18850
18851            let (buffer, range, _) = if selection.reversed {
18852                buffer_ranges.first()
18853            } else {
18854                buffer_ranges.last()
18855            }?;
18856
18857            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18858                ..text::ToPoint::to_point(&range.end, &buffer).row;
18859            Some((
18860                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18861                selection,
18862            ))
18863        });
18864
18865        let Some((buffer, selection)) = buffer_and_selection else {
18866            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18867        };
18868
18869        let Some(project) = self.project.as_ref() else {
18870            return Task::ready(Err(anyhow!("editor does not have project")));
18871        };
18872
18873        project.update(cx, |project, cx| {
18874            project.get_permalink_to_line(&buffer, selection, cx)
18875        })
18876    }
18877
18878    pub fn copy_permalink_to_line(
18879        &mut self,
18880        _: &CopyPermalinkToLine,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        let permalink_task = self.get_permalink_to_line(cx);
18885        let workspace = self.workspace();
18886
18887        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18888            Ok(permalink) => {
18889                cx.update(|_, cx| {
18890                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18891                })
18892                .ok();
18893            }
18894            Err(err) => {
18895                let message = format!("Failed to copy permalink: {err}");
18896
18897                anyhow::Result::<()>::Err(err).log_err();
18898
18899                if let Some(workspace) = workspace {
18900                    workspace
18901                        .update_in(cx, |workspace, _, cx| {
18902                            struct CopyPermalinkToLine;
18903
18904                            workspace.show_toast(
18905                                Toast::new(
18906                                    NotificationId::unique::<CopyPermalinkToLine>(),
18907                                    message,
18908                                ),
18909                                cx,
18910                            )
18911                        })
18912                        .ok();
18913                }
18914            }
18915        })
18916        .detach();
18917    }
18918
18919    pub fn copy_file_location(
18920        &mut self,
18921        _: &CopyFileLocation,
18922        _: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) {
18925        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18926        if let Some(file) = self.target_file(cx) {
18927            if let Some(path) = file.path().to_str() {
18928                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18929            }
18930        }
18931    }
18932
18933    pub fn open_permalink_to_line(
18934        &mut self,
18935        _: &OpenPermalinkToLine,
18936        window: &mut Window,
18937        cx: &mut Context<Self>,
18938    ) {
18939        let permalink_task = self.get_permalink_to_line(cx);
18940        let workspace = self.workspace();
18941
18942        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18943            Ok(permalink) => {
18944                cx.update(|_, cx| {
18945                    cx.open_url(permalink.as_ref());
18946                })
18947                .ok();
18948            }
18949            Err(err) => {
18950                let message = format!("Failed to open permalink: {err}");
18951
18952                anyhow::Result::<()>::Err(err).log_err();
18953
18954                if let Some(workspace) = workspace {
18955                    workspace
18956                        .update(cx, |workspace, cx| {
18957                            struct OpenPermalinkToLine;
18958
18959                            workspace.show_toast(
18960                                Toast::new(
18961                                    NotificationId::unique::<OpenPermalinkToLine>(),
18962                                    message,
18963                                ),
18964                                cx,
18965                            )
18966                        })
18967                        .ok();
18968                }
18969            }
18970        })
18971        .detach();
18972    }
18973
18974    pub fn insert_uuid_v4(
18975        &mut self,
18976        _: &InsertUuidV4,
18977        window: &mut Window,
18978        cx: &mut Context<Self>,
18979    ) {
18980        self.insert_uuid(UuidVersion::V4, window, cx);
18981    }
18982
18983    pub fn insert_uuid_v7(
18984        &mut self,
18985        _: &InsertUuidV7,
18986        window: &mut Window,
18987        cx: &mut Context<Self>,
18988    ) {
18989        self.insert_uuid(UuidVersion::V7, window, cx);
18990    }
18991
18992    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18994        self.transact(window, cx, |this, window, cx| {
18995            let edits = this
18996                .selections
18997                .all::<Point>(cx)
18998                .into_iter()
18999                .map(|selection| {
19000                    let uuid = match version {
19001                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19002                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19003                    };
19004
19005                    (selection.range(), uuid.to_string())
19006                });
19007            this.edit(edits, cx);
19008            this.refresh_inline_completion(true, false, window, cx);
19009        });
19010    }
19011
19012    pub fn open_selections_in_multibuffer(
19013        &mut self,
19014        _: &OpenSelectionsInMultibuffer,
19015        window: &mut Window,
19016        cx: &mut Context<Self>,
19017    ) {
19018        let multibuffer = self.buffer.read(cx);
19019
19020        let Some(buffer) = multibuffer.as_singleton() else {
19021            return;
19022        };
19023
19024        let Some(workspace) = self.workspace() else {
19025            return;
19026        };
19027
19028        let title = multibuffer.title(cx).to_string();
19029
19030        let locations = self
19031            .selections
19032            .all_anchors(cx)
19033            .into_iter()
19034            .map(|selection| Location {
19035                buffer: buffer.clone(),
19036                range: selection.start.text_anchor..selection.end.text_anchor,
19037            })
19038            .collect::<Vec<_>>();
19039
19040        cx.spawn_in(window, async move |_, cx| {
19041            workspace.update_in(cx, |workspace, window, cx| {
19042                Self::open_locations_in_multibuffer(
19043                    workspace,
19044                    locations,
19045                    format!("Selections for '{title}'"),
19046                    false,
19047                    MultibufferSelectionMode::All,
19048                    window,
19049                    cx,
19050                );
19051            })
19052        })
19053        .detach();
19054    }
19055
19056    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19057    /// last highlight added will be used.
19058    ///
19059    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19060    pub fn highlight_rows<T: 'static>(
19061        &mut self,
19062        range: Range<Anchor>,
19063        color: Hsla,
19064        options: RowHighlightOptions,
19065        cx: &mut Context<Self>,
19066    ) {
19067        let snapshot = self.buffer().read(cx).snapshot(cx);
19068        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19069        let ix = row_highlights.binary_search_by(|highlight| {
19070            Ordering::Equal
19071                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19072                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19073        });
19074
19075        if let Err(mut ix) = ix {
19076            let index = post_inc(&mut self.highlight_order);
19077
19078            // If this range intersects with the preceding highlight, then merge it with
19079            // the preceding highlight. Otherwise insert a new highlight.
19080            let mut merged = false;
19081            if ix > 0 {
19082                let prev_highlight = &mut row_highlights[ix - 1];
19083                if prev_highlight
19084                    .range
19085                    .end
19086                    .cmp(&range.start, &snapshot)
19087                    .is_ge()
19088                {
19089                    ix -= 1;
19090                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19091                        prev_highlight.range.end = range.end;
19092                    }
19093                    merged = true;
19094                    prev_highlight.index = index;
19095                    prev_highlight.color = color;
19096                    prev_highlight.options = options;
19097                }
19098            }
19099
19100            if !merged {
19101                row_highlights.insert(
19102                    ix,
19103                    RowHighlight {
19104                        range: range.clone(),
19105                        index,
19106                        color,
19107                        options,
19108                        type_id: TypeId::of::<T>(),
19109                    },
19110                );
19111            }
19112
19113            // If any of the following highlights intersect with this one, merge them.
19114            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19115                let highlight = &row_highlights[ix];
19116                if next_highlight
19117                    .range
19118                    .start
19119                    .cmp(&highlight.range.end, &snapshot)
19120                    .is_le()
19121                {
19122                    if next_highlight
19123                        .range
19124                        .end
19125                        .cmp(&highlight.range.end, &snapshot)
19126                        .is_gt()
19127                    {
19128                        row_highlights[ix].range.end = next_highlight.range.end;
19129                    }
19130                    row_highlights.remove(ix + 1);
19131                } else {
19132                    break;
19133                }
19134            }
19135        }
19136    }
19137
19138    /// Remove any highlighted row ranges of the given type that intersect the
19139    /// given ranges.
19140    pub fn remove_highlighted_rows<T: 'static>(
19141        &mut self,
19142        ranges_to_remove: Vec<Range<Anchor>>,
19143        cx: &mut Context<Self>,
19144    ) {
19145        let snapshot = self.buffer().read(cx).snapshot(cx);
19146        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19147        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19148        row_highlights.retain(|highlight| {
19149            while let Some(range_to_remove) = ranges_to_remove.peek() {
19150                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19151                    Ordering::Less | Ordering::Equal => {
19152                        ranges_to_remove.next();
19153                    }
19154                    Ordering::Greater => {
19155                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19156                            Ordering::Less | Ordering::Equal => {
19157                                return false;
19158                            }
19159                            Ordering::Greater => break,
19160                        }
19161                    }
19162                }
19163            }
19164
19165            true
19166        })
19167    }
19168
19169    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19170    pub fn clear_row_highlights<T: 'static>(&mut self) {
19171        self.highlighted_rows.remove(&TypeId::of::<T>());
19172    }
19173
19174    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19175    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19176        self.highlighted_rows
19177            .get(&TypeId::of::<T>())
19178            .map_or(&[] as &[_], |vec| vec.as_slice())
19179            .iter()
19180            .map(|highlight| (highlight.range.clone(), highlight.color))
19181    }
19182
19183    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19184    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19185    /// Allows to ignore certain kinds of highlights.
19186    pub fn highlighted_display_rows(
19187        &self,
19188        window: &mut Window,
19189        cx: &mut App,
19190    ) -> BTreeMap<DisplayRow, LineHighlight> {
19191        let snapshot = self.snapshot(window, cx);
19192        let mut used_highlight_orders = HashMap::default();
19193        self.highlighted_rows
19194            .iter()
19195            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19196            .fold(
19197                BTreeMap::<DisplayRow, LineHighlight>::new(),
19198                |mut unique_rows, highlight| {
19199                    let start = highlight.range.start.to_display_point(&snapshot);
19200                    let end = highlight.range.end.to_display_point(&snapshot);
19201                    let start_row = start.row().0;
19202                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19203                        && end.column() == 0
19204                    {
19205                        end.row().0.saturating_sub(1)
19206                    } else {
19207                        end.row().0
19208                    };
19209                    for row in start_row..=end_row {
19210                        let used_index =
19211                            used_highlight_orders.entry(row).or_insert(highlight.index);
19212                        if highlight.index >= *used_index {
19213                            *used_index = highlight.index;
19214                            unique_rows.insert(
19215                                DisplayRow(row),
19216                                LineHighlight {
19217                                    include_gutter: highlight.options.include_gutter,
19218                                    border: None,
19219                                    background: highlight.color.into(),
19220                                    type_id: Some(highlight.type_id),
19221                                },
19222                            );
19223                        }
19224                    }
19225                    unique_rows
19226                },
19227            )
19228    }
19229
19230    pub fn highlighted_display_row_for_autoscroll(
19231        &self,
19232        snapshot: &DisplaySnapshot,
19233    ) -> Option<DisplayRow> {
19234        self.highlighted_rows
19235            .values()
19236            .flat_map(|highlighted_rows| highlighted_rows.iter())
19237            .filter_map(|highlight| {
19238                if highlight.options.autoscroll {
19239                    Some(highlight.range.start.to_display_point(snapshot).row())
19240                } else {
19241                    None
19242                }
19243            })
19244            .min()
19245    }
19246
19247    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19248        self.highlight_background::<SearchWithinRange>(
19249            ranges,
19250            |colors| colors.colors().editor_document_highlight_read_background,
19251            cx,
19252        )
19253    }
19254
19255    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19256        self.breadcrumb_header = Some(new_header);
19257    }
19258
19259    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19260        self.clear_background_highlights::<SearchWithinRange>(cx);
19261    }
19262
19263    pub fn highlight_background<T: 'static>(
19264        &mut self,
19265        ranges: &[Range<Anchor>],
19266        color_fetcher: fn(&Theme) -> Hsla,
19267        cx: &mut Context<Self>,
19268    ) {
19269        self.background_highlights.insert(
19270            HighlightKey::Type(TypeId::of::<T>()),
19271            (color_fetcher, Arc::from(ranges)),
19272        );
19273        self.scrollbar_marker_state.dirty = true;
19274        cx.notify();
19275    }
19276
19277    pub fn highlight_background_key<T: 'static>(
19278        &mut self,
19279        key: usize,
19280        ranges: &[Range<Anchor>],
19281        color_fetcher: fn(&Theme) -> Hsla,
19282        cx: &mut Context<Self>,
19283    ) {
19284        self.background_highlights.insert(
19285            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19286            (color_fetcher, Arc::from(ranges)),
19287        );
19288        self.scrollbar_marker_state.dirty = true;
19289        cx.notify();
19290    }
19291
19292    pub fn clear_background_highlights<T: 'static>(
19293        &mut self,
19294        cx: &mut Context<Self>,
19295    ) -> Option<BackgroundHighlight> {
19296        let text_highlights = self
19297            .background_highlights
19298            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19299        if !text_highlights.1.is_empty() {
19300            self.scrollbar_marker_state.dirty = true;
19301            cx.notify();
19302        }
19303        Some(text_highlights)
19304    }
19305
19306    pub fn highlight_gutter<T: 'static>(
19307        &mut self,
19308        ranges: impl Into<Vec<Range<Anchor>>>,
19309        color_fetcher: fn(&App) -> Hsla,
19310        cx: &mut Context<Self>,
19311    ) {
19312        self.gutter_highlights
19313            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19314        cx.notify();
19315    }
19316
19317    pub fn clear_gutter_highlights<T: 'static>(
19318        &mut self,
19319        cx: &mut Context<Self>,
19320    ) -> Option<GutterHighlight> {
19321        cx.notify();
19322        self.gutter_highlights.remove(&TypeId::of::<T>())
19323    }
19324
19325    pub fn insert_gutter_highlight<T: 'static>(
19326        &mut self,
19327        range: Range<Anchor>,
19328        color_fetcher: fn(&App) -> Hsla,
19329        cx: &mut Context<Self>,
19330    ) {
19331        let snapshot = self.buffer().read(cx).snapshot(cx);
19332        let mut highlights = self
19333            .gutter_highlights
19334            .remove(&TypeId::of::<T>())
19335            .map(|(_, highlights)| highlights)
19336            .unwrap_or_default();
19337        let ix = highlights.binary_search_by(|highlight| {
19338            Ordering::Equal
19339                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19340                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19341        });
19342        if let Err(ix) = ix {
19343            highlights.insert(ix, range);
19344        }
19345        self.gutter_highlights
19346            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19347    }
19348
19349    pub fn remove_gutter_highlights<T: 'static>(
19350        &mut self,
19351        ranges_to_remove: Vec<Range<Anchor>>,
19352        cx: &mut Context<Self>,
19353    ) {
19354        let snapshot = self.buffer().read(cx).snapshot(cx);
19355        let Some((color_fetcher, mut gutter_highlights)) =
19356            self.gutter_highlights.remove(&TypeId::of::<T>())
19357        else {
19358            return;
19359        };
19360        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19361        gutter_highlights.retain(|highlight| {
19362            while let Some(range_to_remove) = ranges_to_remove.peek() {
19363                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19364                    Ordering::Less | Ordering::Equal => {
19365                        ranges_to_remove.next();
19366                    }
19367                    Ordering::Greater => {
19368                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19369                            Ordering::Less | Ordering::Equal => {
19370                                return false;
19371                            }
19372                            Ordering::Greater => break,
19373                        }
19374                    }
19375                }
19376            }
19377
19378            true
19379        });
19380        self.gutter_highlights
19381            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19382    }
19383
19384    #[cfg(feature = "test-support")]
19385    pub fn all_text_highlights(
19386        &self,
19387        window: &mut Window,
19388        cx: &mut Context<Self>,
19389    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19390        let snapshot = self.snapshot(window, cx);
19391        self.display_map.update(cx, |display_map, _| {
19392            display_map
19393                .all_text_highlights()
19394                .map(|highlight| {
19395                    let (style, ranges) = highlight.as_ref();
19396                    (
19397                        *style,
19398                        ranges
19399                            .iter()
19400                            .map(|range| range.clone().to_display_points(&snapshot))
19401                            .collect(),
19402                    )
19403                })
19404                .collect()
19405        })
19406    }
19407
19408    #[cfg(feature = "test-support")]
19409    pub fn all_text_background_highlights(
19410        &self,
19411        window: &mut Window,
19412        cx: &mut Context<Self>,
19413    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19414        let snapshot = self.snapshot(window, cx);
19415        let buffer = &snapshot.buffer_snapshot;
19416        let start = buffer.anchor_before(0);
19417        let end = buffer.anchor_after(buffer.len());
19418        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19419    }
19420
19421    #[cfg(feature = "test-support")]
19422    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19423        let snapshot = self.buffer().read(cx).snapshot(cx);
19424
19425        let highlights = self
19426            .background_highlights
19427            .get(&HighlightKey::Type(TypeId::of::<
19428                items::BufferSearchHighlights,
19429            >()));
19430
19431        if let Some((_color, ranges)) = highlights {
19432            ranges
19433                .iter()
19434                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19435                .collect_vec()
19436        } else {
19437            vec![]
19438        }
19439    }
19440
19441    fn document_highlights_for_position<'a>(
19442        &'a self,
19443        position: Anchor,
19444        buffer: &'a MultiBufferSnapshot,
19445    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19446        let read_highlights = self
19447            .background_highlights
19448            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19449            .map(|h| &h.1);
19450        let write_highlights = self
19451            .background_highlights
19452            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19453            .map(|h| &h.1);
19454        let left_position = position.bias_left(buffer);
19455        let right_position = position.bias_right(buffer);
19456        read_highlights
19457            .into_iter()
19458            .chain(write_highlights)
19459            .flat_map(move |ranges| {
19460                let start_ix = match ranges.binary_search_by(|probe| {
19461                    let cmp = probe.end.cmp(&left_position, buffer);
19462                    if cmp.is_ge() {
19463                        Ordering::Greater
19464                    } else {
19465                        Ordering::Less
19466                    }
19467                }) {
19468                    Ok(i) | Err(i) => i,
19469                };
19470
19471                ranges[start_ix..]
19472                    .iter()
19473                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19474            })
19475    }
19476
19477    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19478        self.background_highlights
19479            .get(&HighlightKey::Type(TypeId::of::<T>()))
19480            .map_or(false, |(_, highlights)| !highlights.is_empty())
19481    }
19482
19483    pub fn background_highlights_in_range(
19484        &self,
19485        search_range: Range<Anchor>,
19486        display_snapshot: &DisplaySnapshot,
19487        theme: &Theme,
19488    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19489        let mut results = Vec::new();
19490        for (color_fetcher, ranges) in self.background_highlights.values() {
19491            let color = color_fetcher(theme);
19492            let start_ix = match ranges.binary_search_by(|probe| {
19493                let cmp = probe
19494                    .end
19495                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19496                if cmp.is_gt() {
19497                    Ordering::Greater
19498                } else {
19499                    Ordering::Less
19500                }
19501            }) {
19502                Ok(i) | Err(i) => i,
19503            };
19504            for range in &ranges[start_ix..] {
19505                if range
19506                    .start
19507                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19508                    .is_ge()
19509                {
19510                    break;
19511                }
19512
19513                let start = range.start.to_display_point(display_snapshot);
19514                let end = range.end.to_display_point(display_snapshot);
19515                results.push((start..end, color))
19516            }
19517        }
19518        results
19519    }
19520
19521    pub fn background_highlight_row_ranges<T: 'static>(
19522        &self,
19523        search_range: Range<Anchor>,
19524        display_snapshot: &DisplaySnapshot,
19525        count: usize,
19526    ) -> Vec<RangeInclusive<DisplayPoint>> {
19527        let mut results = Vec::new();
19528        let Some((_, ranges)) = self
19529            .background_highlights
19530            .get(&HighlightKey::Type(TypeId::of::<T>()))
19531        else {
19532            return vec![];
19533        };
19534
19535        let start_ix = match ranges.binary_search_by(|probe| {
19536            let cmp = probe
19537                .end
19538                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19539            if cmp.is_gt() {
19540                Ordering::Greater
19541            } else {
19542                Ordering::Less
19543            }
19544        }) {
19545            Ok(i) | Err(i) => i,
19546        };
19547        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19548            if let (Some(start_display), Some(end_display)) = (start, end) {
19549                results.push(
19550                    start_display.to_display_point(display_snapshot)
19551                        ..=end_display.to_display_point(display_snapshot),
19552                );
19553            }
19554        };
19555        let mut start_row: Option<Point> = None;
19556        let mut end_row: Option<Point> = None;
19557        if ranges.len() > count {
19558            return Vec::new();
19559        }
19560        for range in &ranges[start_ix..] {
19561            if range
19562                .start
19563                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19564                .is_ge()
19565            {
19566                break;
19567            }
19568            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19569            if let Some(current_row) = &end_row {
19570                if end.row == current_row.row {
19571                    continue;
19572                }
19573            }
19574            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19575            if start_row.is_none() {
19576                assert_eq!(end_row, None);
19577                start_row = Some(start);
19578                end_row = Some(end);
19579                continue;
19580            }
19581            if let Some(current_end) = end_row.as_mut() {
19582                if start.row > current_end.row + 1 {
19583                    push_region(start_row, end_row);
19584                    start_row = Some(start);
19585                    end_row = Some(end);
19586                } else {
19587                    // Merge two hunks.
19588                    *current_end = end;
19589                }
19590            } else {
19591                unreachable!();
19592            }
19593        }
19594        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19595        push_region(start_row, end_row);
19596        results
19597    }
19598
19599    pub fn gutter_highlights_in_range(
19600        &self,
19601        search_range: Range<Anchor>,
19602        display_snapshot: &DisplaySnapshot,
19603        cx: &App,
19604    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19605        let mut results = Vec::new();
19606        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19607            let color = color_fetcher(cx);
19608            let start_ix = match ranges.binary_search_by(|probe| {
19609                let cmp = probe
19610                    .end
19611                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19612                if cmp.is_gt() {
19613                    Ordering::Greater
19614                } else {
19615                    Ordering::Less
19616                }
19617            }) {
19618                Ok(i) | Err(i) => i,
19619            };
19620            for range in &ranges[start_ix..] {
19621                if range
19622                    .start
19623                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19624                    .is_ge()
19625                {
19626                    break;
19627                }
19628
19629                let start = range.start.to_display_point(display_snapshot);
19630                let end = range.end.to_display_point(display_snapshot);
19631                results.push((start..end, color))
19632            }
19633        }
19634        results
19635    }
19636
19637    /// Get the text ranges corresponding to the redaction query
19638    pub fn redacted_ranges(
19639        &self,
19640        search_range: Range<Anchor>,
19641        display_snapshot: &DisplaySnapshot,
19642        cx: &App,
19643    ) -> Vec<Range<DisplayPoint>> {
19644        display_snapshot
19645            .buffer_snapshot
19646            .redacted_ranges(search_range, |file| {
19647                if let Some(file) = file {
19648                    file.is_private()
19649                        && EditorSettings::get(
19650                            Some(SettingsLocation {
19651                                worktree_id: file.worktree_id(cx),
19652                                path: file.path().as_ref(),
19653                            }),
19654                            cx,
19655                        )
19656                        .redact_private_values
19657                } else {
19658                    false
19659                }
19660            })
19661            .map(|range| {
19662                range.start.to_display_point(display_snapshot)
19663                    ..range.end.to_display_point(display_snapshot)
19664            })
19665            .collect()
19666    }
19667
19668    pub fn highlight_text_key<T: 'static>(
19669        &mut self,
19670        key: usize,
19671        ranges: Vec<Range<Anchor>>,
19672        style: HighlightStyle,
19673        cx: &mut Context<Self>,
19674    ) {
19675        self.display_map.update(cx, |map, _| {
19676            map.highlight_text(
19677                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19678                ranges,
19679                style,
19680            );
19681        });
19682        cx.notify();
19683    }
19684
19685    pub fn highlight_text<T: 'static>(
19686        &mut self,
19687        ranges: Vec<Range<Anchor>>,
19688        style: HighlightStyle,
19689        cx: &mut Context<Self>,
19690    ) {
19691        self.display_map.update(cx, |map, _| {
19692            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19693        });
19694        cx.notify();
19695    }
19696
19697    pub(crate) fn highlight_inlays<T: 'static>(
19698        &mut self,
19699        highlights: Vec<InlayHighlight>,
19700        style: HighlightStyle,
19701        cx: &mut Context<Self>,
19702    ) {
19703        self.display_map.update(cx, |map, _| {
19704            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19705        });
19706        cx.notify();
19707    }
19708
19709    pub fn text_highlights<'a, T: 'static>(
19710        &'a self,
19711        cx: &'a App,
19712    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19713        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19714    }
19715
19716    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19717        let cleared = self
19718            .display_map
19719            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19720        if cleared {
19721            cx.notify();
19722        }
19723    }
19724
19725    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19726        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19727            && self.focus_handle.is_focused(window)
19728    }
19729
19730    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19731        self.show_cursor_when_unfocused = is_enabled;
19732        cx.notify();
19733    }
19734
19735    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19736        cx.notify();
19737    }
19738
19739    fn on_debug_session_event(
19740        &mut self,
19741        _session: Entity<Session>,
19742        event: &SessionEvent,
19743        cx: &mut Context<Self>,
19744    ) {
19745        match event {
19746            SessionEvent::InvalidateInlineValue => {
19747                self.refresh_inline_values(cx);
19748            }
19749            _ => {}
19750        }
19751    }
19752
19753    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19754        let Some(project) = self.project.clone() else {
19755            return;
19756        };
19757
19758        if !self.inline_value_cache.enabled {
19759            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19760            self.splice_inlays(&inlays, Vec::new(), cx);
19761            return;
19762        }
19763
19764        let current_execution_position = self
19765            .highlighted_rows
19766            .get(&TypeId::of::<ActiveDebugLine>())
19767            .and_then(|lines| lines.last().map(|line| line.range.end));
19768
19769        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19770            let inline_values = editor
19771                .update(cx, |editor, cx| {
19772                    let Some(current_execution_position) = current_execution_position else {
19773                        return Some(Task::ready(Ok(Vec::new())));
19774                    };
19775
19776                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19777                        let snapshot = buffer.snapshot(cx);
19778
19779                        let excerpt = snapshot.excerpt_containing(
19780                            current_execution_position..current_execution_position,
19781                        )?;
19782
19783                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19784                    })?;
19785
19786                    let range =
19787                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19788
19789                    project.inline_values(buffer, range, cx)
19790                })
19791                .ok()
19792                .flatten()?
19793                .await
19794                .context("refreshing debugger inlays")
19795                .log_err()?;
19796
19797            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19798
19799            for (buffer_id, inline_value) in inline_values
19800                .into_iter()
19801                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19802            {
19803                buffer_inline_values
19804                    .entry(buffer_id)
19805                    .or_default()
19806                    .push(inline_value);
19807            }
19808
19809            editor
19810                .update(cx, |editor, cx| {
19811                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19812                    let mut new_inlays = Vec::default();
19813
19814                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19815                        let buffer_id = buffer_snapshot.remote_id();
19816                        buffer_inline_values
19817                            .get(&buffer_id)
19818                            .into_iter()
19819                            .flatten()
19820                            .for_each(|hint| {
19821                                let inlay = Inlay::debugger(
19822                                    post_inc(&mut editor.next_inlay_id),
19823                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19824                                    hint.text(),
19825                                );
19826                                if !inlay.text.chars().contains(&'\n') {
19827                                    new_inlays.push(inlay);
19828                                }
19829                            });
19830                    }
19831
19832                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19833                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19834
19835                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19836                })
19837                .ok()?;
19838            Some(())
19839        });
19840    }
19841
19842    fn on_buffer_event(
19843        &mut self,
19844        multibuffer: &Entity<MultiBuffer>,
19845        event: &multi_buffer::Event,
19846        window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        match event {
19850            multi_buffer::Event::Edited {
19851                singleton_buffer_edited,
19852                edited_buffer,
19853            } => {
19854                self.scrollbar_marker_state.dirty = true;
19855                self.active_indent_guides_state.dirty = true;
19856                self.refresh_active_diagnostics(cx);
19857                self.refresh_code_actions(window, cx);
19858                self.refresh_selected_text_highlights(true, window, cx);
19859                self.refresh_single_line_folds(window, cx);
19860                refresh_matching_bracket_highlights(self, window, cx);
19861                if self.has_active_inline_completion() {
19862                    self.update_visible_inline_completion(window, cx);
19863                }
19864                if let Some(project) = self.project.as_ref() {
19865                    if let Some(edited_buffer) = edited_buffer {
19866                        project.update(cx, |project, cx| {
19867                            self.registered_buffers
19868                                .entry(edited_buffer.read(cx).remote_id())
19869                                .or_insert_with(|| {
19870                                    project
19871                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19872                                });
19873                        });
19874                    }
19875                }
19876                cx.emit(EditorEvent::BufferEdited);
19877                cx.emit(SearchEvent::MatchesInvalidated);
19878
19879                if let Some(buffer) = edited_buffer {
19880                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19881                }
19882
19883                if *singleton_buffer_edited {
19884                    if let Some(buffer) = edited_buffer {
19885                        if buffer.read(cx).file().is_none() {
19886                            cx.emit(EditorEvent::TitleChanged);
19887                        }
19888                    }
19889                    if let Some(project) = &self.project {
19890                        #[allow(clippy::mutable_key_type)]
19891                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19892                            multibuffer
19893                                .all_buffers()
19894                                .into_iter()
19895                                .filter_map(|buffer| {
19896                                    buffer.update(cx, |buffer, cx| {
19897                                        let language = buffer.language()?;
19898                                        let should_discard = project.update(cx, |project, cx| {
19899                                            project.is_local()
19900                                                && !project.has_language_servers_for(buffer, cx)
19901                                        });
19902                                        should_discard.not().then_some(language.clone())
19903                                    })
19904                                })
19905                                .collect::<HashSet<_>>()
19906                        });
19907                        if !languages_affected.is_empty() {
19908                            self.refresh_inlay_hints(
19909                                InlayHintRefreshReason::BufferEdited(languages_affected),
19910                                cx,
19911                            );
19912                        }
19913                    }
19914                }
19915
19916                let Some(project) = &self.project else { return };
19917                let (telemetry, is_via_ssh) = {
19918                    let project = project.read(cx);
19919                    let telemetry = project.client().telemetry().clone();
19920                    let is_via_ssh = project.is_via_ssh();
19921                    (telemetry, is_via_ssh)
19922                };
19923                refresh_linked_ranges(self, window, cx);
19924                telemetry.log_edit_event("editor", is_via_ssh);
19925            }
19926            multi_buffer::Event::ExcerptsAdded {
19927                buffer,
19928                predecessor,
19929                excerpts,
19930            } => {
19931                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19932                let buffer_id = buffer.read(cx).remote_id();
19933                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19934                    if let Some(project) = &self.project {
19935                        update_uncommitted_diff_for_buffer(
19936                            cx.entity(),
19937                            project,
19938                            [buffer.clone()],
19939                            self.buffer.clone(),
19940                            cx,
19941                        )
19942                        .detach();
19943                    }
19944                }
19945                self.update_lsp_data(false, Some(buffer_id), window, cx);
19946                cx.emit(EditorEvent::ExcerptsAdded {
19947                    buffer: buffer.clone(),
19948                    predecessor: *predecessor,
19949                    excerpts: excerpts.clone(),
19950                });
19951                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19952            }
19953            multi_buffer::Event::ExcerptsRemoved {
19954                ids,
19955                removed_buffer_ids,
19956            } => {
19957                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19958                let buffer = self.buffer.read(cx);
19959                self.registered_buffers
19960                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19961                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19962                cx.emit(EditorEvent::ExcerptsRemoved {
19963                    ids: ids.clone(),
19964                    removed_buffer_ids: removed_buffer_ids.clone(),
19965                });
19966            }
19967            multi_buffer::Event::ExcerptsEdited {
19968                excerpt_ids,
19969                buffer_ids,
19970            } => {
19971                self.display_map.update(cx, |map, cx| {
19972                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19973                });
19974                cx.emit(EditorEvent::ExcerptsEdited {
19975                    ids: excerpt_ids.clone(),
19976                });
19977            }
19978            multi_buffer::Event::ExcerptsExpanded { ids } => {
19979                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19980                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19981            }
19982            multi_buffer::Event::Reparsed(buffer_id) => {
19983                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19984                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19985
19986                cx.emit(EditorEvent::Reparsed(*buffer_id));
19987            }
19988            multi_buffer::Event::DiffHunksToggled => {
19989                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19990            }
19991            multi_buffer::Event::LanguageChanged(buffer_id) => {
19992                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19993                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19994                cx.emit(EditorEvent::Reparsed(*buffer_id));
19995                cx.notify();
19996            }
19997            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19998            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19999            multi_buffer::Event::FileHandleChanged
20000            | multi_buffer::Event::Reloaded
20001            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20002            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20003            multi_buffer::Event::DiagnosticsUpdated => {
20004                self.update_diagnostics_state(window, cx);
20005            }
20006            _ => {}
20007        };
20008    }
20009
20010    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20011        if !self.diagnostics_enabled() {
20012            return;
20013        }
20014        self.refresh_active_diagnostics(cx);
20015        self.refresh_inline_diagnostics(true, window, cx);
20016        self.scrollbar_marker_state.dirty = true;
20017        cx.notify();
20018    }
20019
20020    pub fn start_temporary_diff_override(&mut self) {
20021        self.load_diff_task.take();
20022        self.temporary_diff_override = true;
20023    }
20024
20025    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20026        self.temporary_diff_override = false;
20027        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20028        self.buffer.update(cx, |buffer, cx| {
20029            buffer.set_all_diff_hunks_collapsed(cx);
20030        });
20031
20032        if let Some(project) = self.project.clone() {
20033            self.load_diff_task = Some(
20034                update_uncommitted_diff_for_buffer(
20035                    cx.entity(),
20036                    &project,
20037                    self.buffer.read(cx).all_buffers(),
20038                    self.buffer.clone(),
20039                    cx,
20040                )
20041                .shared(),
20042            );
20043        }
20044    }
20045
20046    fn on_display_map_changed(
20047        &mut self,
20048        _: Entity<DisplayMap>,
20049        _: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        cx.notify();
20053    }
20054
20055    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20056        if self.diagnostics_enabled() {
20057            let new_severity = EditorSettings::get_global(cx)
20058                .diagnostics_max_severity
20059                .unwrap_or(DiagnosticSeverity::Hint);
20060            self.set_max_diagnostics_severity(new_severity, cx);
20061        }
20062        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20063        self.update_edit_prediction_settings(cx);
20064        self.refresh_inline_completion(true, false, window, cx);
20065        self.refresh_inline_values(cx);
20066        self.refresh_inlay_hints(
20067            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20068                self.selections.newest_anchor().head(),
20069                &self.buffer.read(cx).snapshot(cx),
20070                cx,
20071            )),
20072            cx,
20073        );
20074
20075        let old_cursor_shape = self.cursor_shape;
20076
20077        {
20078            let editor_settings = EditorSettings::get_global(cx);
20079            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20080            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20081            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20082            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20083        }
20084
20085        if old_cursor_shape != self.cursor_shape {
20086            cx.emit(EditorEvent::CursorShapeChanged);
20087        }
20088
20089        let project_settings = ProjectSettings::get_global(cx);
20090        self.serialize_dirty_buffers =
20091            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20092
20093        if self.mode.is_full() {
20094            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20095            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20096            if self.show_inline_diagnostics != show_inline_diagnostics {
20097                self.show_inline_diagnostics = show_inline_diagnostics;
20098                self.refresh_inline_diagnostics(false, window, cx);
20099            }
20100
20101            if self.git_blame_inline_enabled != inline_blame_enabled {
20102                self.toggle_git_blame_inline_internal(false, window, cx);
20103            }
20104
20105            let minimap_settings = EditorSettings::get_global(cx).minimap;
20106            if self.minimap_visibility != MinimapVisibility::Disabled {
20107                if self.minimap_visibility.settings_visibility()
20108                    != minimap_settings.minimap_enabled()
20109                {
20110                    self.set_minimap_visibility(
20111                        MinimapVisibility::for_mode(self.mode(), cx),
20112                        window,
20113                        cx,
20114                    );
20115                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20116                    minimap_entity.update(cx, |minimap_editor, cx| {
20117                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20118                    })
20119                }
20120            }
20121        }
20122
20123        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20124            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20125        }) {
20126            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20127                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20128            }
20129            self.refresh_colors(false, None, window, cx);
20130        }
20131
20132        cx.notify();
20133    }
20134
20135    pub fn set_searchable(&mut self, searchable: bool) {
20136        self.searchable = searchable;
20137    }
20138
20139    pub fn searchable(&self) -> bool {
20140        self.searchable
20141    }
20142
20143    fn open_proposed_changes_editor(
20144        &mut self,
20145        _: &OpenProposedChangesEditor,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        let Some(workspace) = self.workspace() else {
20150            cx.propagate();
20151            return;
20152        };
20153
20154        let selections = self.selections.all::<usize>(cx);
20155        let multi_buffer = self.buffer.read(cx);
20156        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20157        let mut new_selections_by_buffer = HashMap::default();
20158        for selection in selections {
20159            for (buffer, range, _) in
20160                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20161            {
20162                let mut range = range.to_point(buffer);
20163                range.start.column = 0;
20164                range.end.column = buffer.line_len(range.end.row);
20165                new_selections_by_buffer
20166                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20167                    .or_insert(Vec::new())
20168                    .push(range)
20169            }
20170        }
20171
20172        let proposed_changes_buffers = new_selections_by_buffer
20173            .into_iter()
20174            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20175            .collect::<Vec<_>>();
20176        let proposed_changes_editor = cx.new(|cx| {
20177            ProposedChangesEditor::new(
20178                "Proposed changes",
20179                proposed_changes_buffers,
20180                self.project.clone(),
20181                window,
20182                cx,
20183            )
20184        });
20185
20186        window.defer(cx, move |window, cx| {
20187            workspace.update(cx, |workspace, cx| {
20188                workspace.active_pane().update(cx, |pane, cx| {
20189                    pane.add_item(
20190                        Box::new(proposed_changes_editor),
20191                        true,
20192                        true,
20193                        None,
20194                        window,
20195                        cx,
20196                    );
20197                });
20198            });
20199        });
20200    }
20201
20202    pub fn open_excerpts_in_split(
20203        &mut self,
20204        _: &OpenExcerptsSplit,
20205        window: &mut Window,
20206        cx: &mut Context<Self>,
20207    ) {
20208        self.open_excerpts_common(None, true, window, cx)
20209    }
20210
20211    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20212        self.open_excerpts_common(None, false, window, cx)
20213    }
20214
20215    fn open_excerpts_common(
20216        &mut self,
20217        jump_data: Option<JumpData>,
20218        split: bool,
20219        window: &mut Window,
20220        cx: &mut Context<Self>,
20221    ) {
20222        let Some(workspace) = self.workspace() else {
20223            cx.propagate();
20224            return;
20225        };
20226
20227        if self.buffer.read(cx).is_singleton() {
20228            cx.propagate();
20229            return;
20230        }
20231
20232        let mut new_selections_by_buffer = HashMap::default();
20233        match &jump_data {
20234            Some(JumpData::MultiBufferPoint {
20235                excerpt_id,
20236                position,
20237                anchor,
20238                line_offset_from_top,
20239            }) => {
20240                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20241                if let Some(buffer) = multi_buffer_snapshot
20242                    .buffer_id_for_excerpt(*excerpt_id)
20243                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20244                {
20245                    let buffer_snapshot = buffer.read(cx).snapshot();
20246                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20247                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20248                    } else {
20249                        buffer_snapshot.clip_point(*position, Bias::Left)
20250                    };
20251                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20252                    new_selections_by_buffer.insert(
20253                        buffer,
20254                        (
20255                            vec![jump_to_offset..jump_to_offset],
20256                            Some(*line_offset_from_top),
20257                        ),
20258                    );
20259                }
20260            }
20261            Some(JumpData::MultiBufferRow {
20262                row,
20263                line_offset_from_top,
20264            }) => {
20265                let point = MultiBufferPoint::new(row.0, 0);
20266                if let Some((buffer, buffer_point, _)) =
20267                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20268                {
20269                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20270                    new_selections_by_buffer
20271                        .entry(buffer)
20272                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20273                        .0
20274                        .push(buffer_offset..buffer_offset)
20275                }
20276            }
20277            None => {
20278                let selections = self.selections.all::<usize>(cx);
20279                let multi_buffer = self.buffer.read(cx);
20280                for selection in selections {
20281                    for (snapshot, range, _, anchor) in multi_buffer
20282                        .snapshot(cx)
20283                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20284                    {
20285                        if let Some(anchor) = anchor {
20286                            // selection is in a deleted hunk
20287                            let Some(buffer_id) = anchor.buffer_id else {
20288                                continue;
20289                            };
20290                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20291                                continue;
20292                            };
20293                            let offset = text::ToOffset::to_offset(
20294                                &anchor.text_anchor,
20295                                &buffer_handle.read(cx).snapshot(),
20296                            );
20297                            let range = offset..offset;
20298                            new_selections_by_buffer
20299                                .entry(buffer_handle)
20300                                .or_insert((Vec::new(), None))
20301                                .0
20302                                .push(range)
20303                        } else {
20304                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20305                            else {
20306                                continue;
20307                            };
20308                            new_selections_by_buffer
20309                                .entry(buffer_handle)
20310                                .or_insert((Vec::new(), None))
20311                                .0
20312                                .push(range)
20313                        }
20314                    }
20315                }
20316            }
20317        }
20318
20319        new_selections_by_buffer
20320            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20321
20322        if new_selections_by_buffer.is_empty() {
20323            return;
20324        }
20325
20326        // We defer the pane interaction because we ourselves are a workspace item
20327        // and activating a new item causes the pane to call a method on us reentrantly,
20328        // which panics if we're on the stack.
20329        window.defer(cx, move |window, cx| {
20330            workspace.update(cx, |workspace, cx| {
20331                let pane = if split {
20332                    workspace.adjacent_pane(window, cx)
20333                } else {
20334                    workspace.active_pane().clone()
20335                };
20336
20337                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20338                    let editor = buffer
20339                        .read(cx)
20340                        .file()
20341                        .is_none()
20342                        .then(|| {
20343                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20344                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20345                            // Instead, we try to activate the existing editor in the pane first.
20346                            let (editor, pane_item_index) =
20347                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20348                                    let editor = item.downcast::<Editor>()?;
20349                                    let singleton_buffer =
20350                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20351                                    if singleton_buffer == buffer {
20352                                        Some((editor, i))
20353                                    } else {
20354                                        None
20355                                    }
20356                                })?;
20357                            pane.update(cx, |pane, cx| {
20358                                pane.activate_item(pane_item_index, true, true, window, cx)
20359                            });
20360                            Some(editor)
20361                        })
20362                        .flatten()
20363                        .unwrap_or_else(|| {
20364                            workspace.open_project_item::<Self>(
20365                                pane.clone(),
20366                                buffer,
20367                                true,
20368                                true,
20369                                window,
20370                                cx,
20371                            )
20372                        });
20373
20374                    editor.update(cx, |editor, cx| {
20375                        let autoscroll = match scroll_offset {
20376                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20377                            None => Autoscroll::newest(),
20378                        };
20379                        let nav_history = editor.nav_history.take();
20380                        editor.change_selections(
20381                            SelectionEffects::scroll(autoscroll),
20382                            window,
20383                            cx,
20384                            |s| {
20385                                s.select_ranges(ranges);
20386                            },
20387                        );
20388                        editor.nav_history = nav_history;
20389                    });
20390                }
20391            })
20392        });
20393    }
20394
20395    // For now, don't allow opening excerpts in buffers that aren't backed by
20396    // regular project files.
20397    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20398        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20399    }
20400
20401    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20402        let snapshot = self.buffer.read(cx).read(cx);
20403        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20404        Some(
20405            ranges
20406                .iter()
20407                .map(move |range| {
20408                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20409                })
20410                .collect(),
20411        )
20412    }
20413
20414    fn selection_replacement_ranges(
20415        &self,
20416        range: Range<OffsetUtf16>,
20417        cx: &mut App,
20418    ) -> Vec<Range<OffsetUtf16>> {
20419        let selections = self.selections.all::<OffsetUtf16>(cx);
20420        let newest_selection = selections
20421            .iter()
20422            .max_by_key(|selection| selection.id)
20423            .unwrap();
20424        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20425        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20426        let snapshot = self.buffer.read(cx).read(cx);
20427        selections
20428            .into_iter()
20429            .map(|mut selection| {
20430                selection.start.0 =
20431                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20432                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20433                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20434                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20435            })
20436            .collect()
20437    }
20438
20439    fn report_editor_event(
20440        &self,
20441        event_type: &'static str,
20442        file_extension: Option<String>,
20443        cx: &App,
20444    ) {
20445        if cfg!(any(test, feature = "test-support")) {
20446            return;
20447        }
20448
20449        let Some(project) = &self.project else { return };
20450
20451        // If None, we are in a file without an extension
20452        let file = self
20453            .buffer
20454            .read(cx)
20455            .as_singleton()
20456            .and_then(|b| b.read(cx).file());
20457        let file_extension = file_extension.or(file
20458            .as_ref()
20459            .and_then(|file| Path::new(file.file_name(cx)).extension())
20460            .and_then(|e| e.to_str())
20461            .map(|a| a.to_string()));
20462
20463        let vim_mode = vim_enabled(cx);
20464
20465        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20466        let copilot_enabled = edit_predictions_provider
20467            == language::language_settings::EditPredictionProvider::Copilot;
20468        let copilot_enabled_for_language = self
20469            .buffer
20470            .read(cx)
20471            .language_settings(cx)
20472            .show_edit_predictions;
20473
20474        let project = project.read(cx);
20475        telemetry::event!(
20476            event_type,
20477            file_extension,
20478            vim_mode,
20479            copilot_enabled,
20480            copilot_enabled_for_language,
20481            edit_predictions_provider,
20482            is_via_ssh = project.is_via_ssh(),
20483        );
20484    }
20485
20486    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20487    /// with each line being an array of {text, highlight} objects.
20488    fn copy_highlight_json(
20489        &mut self,
20490        _: &CopyHighlightJson,
20491        window: &mut Window,
20492        cx: &mut Context<Self>,
20493    ) {
20494        #[derive(Serialize)]
20495        struct Chunk<'a> {
20496            text: String,
20497            highlight: Option<&'a str>,
20498        }
20499
20500        let snapshot = self.buffer.read(cx).snapshot(cx);
20501        let range = self
20502            .selected_text_range(false, window, cx)
20503            .and_then(|selection| {
20504                if selection.range.is_empty() {
20505                    None
20506                } else {
20507                    Some(selection.range)
20508                }
20509            })
20510            .unwrap_or_else(|| 0..snapshot.len());
20511
20512        let chunks = snapshot.chunks(range, true);
20513        let mut lines = Vec::new();
20514        let mut line: VecDeque<Chunk> = VecDeque::new();
20515
20516        let Some(style) = self.style.as_ref() else {
20517            return;
20518        };
20519
20520        for chunk in chunks {
20521            let highlight = chunk
20522                .syntax_highlight_id
20523                .and_then(|id| id.name(&style.syntax));
20524            let mut chunk_lines = chunk.text.split('\n').peekable();
20525            while let Some(text) = chunk_lines.next() {
20526                let mut merged_with_last_token = false;
20527                if let Some(last_token) = line.back_mut() {
20528                    if last_token.highlight == highlight {
20529                        last_token.text.push_str(text);
20530                        merged_with_last_token = true;
20531                    }
20532                }
20533
20534                if !merged_with_last_token {
20535                    line.push_back(Chunk {
20536                        text: text.into(),
20537                        highlight,
20538                    });
20539                }
20540
20541                if chunk_lines.peek().is_some() {
20542                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20543                        line.pop_front();
20544                    }
20545                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20546                        line.pop_back();
20547                    }
20548
20549                    lines.push(mem::take(&mut line));
20550                }
20551            }
20552        }
20553
20554        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20555            return;
20556        };
20557        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20558    }
20559
20560    pub fn open_context_menu(
20561        &mut self,
20562        _: &OpenContextMenu,
20563        window: &mut Window,
20564        cx: &mut Context<Self>,
20565    ) {
20566        self.request_autoscroll(Autoscroll::newest(), cx);
20567        let position = self.selections.newest_display(cx).start;
20568        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20569    }
20570
20571    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20572        &self.inlay_hint_cache
20573    }
20574
20575    pub fn replay_insert_event(
20576        &mut self,
20577        text: &str,
20578        relative_utf16_range: Option<Range<isize>>,
20579        window: &mut Window,
20580        cx: &mut Context<Self>,
20581    ) {
20582        if !self.input_enabled {
20583            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20584            return;
20585        }
20586        if let Some(relative_utf16_range) = relative_utf16_range {
20587            let selections = self.selections.all::<OffsetUtf16>(cx);
20588            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20589                let new_ranges = selections.into_iter().map(|range| {
20590                    let start = OffsetUtf16(
20591                        range
20592                            .head()
20593                            .0
20594                            .saturating_add_signed(relative_utf16_range.start),
20595                    );
20596                    let end = OffsetUtf16(
20597                        range
20598                            .head()
20599                            .0
20600                            .saturating_add_signed(relative_utf16_range.end),
20601                    );
20602                    start..end
20603                });
20604                s.select_ranges(new_ranges);
20605            });
20606        }
20607
20608        self.handle_input(text, window, cx);
20609    }
20610
20611    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20612        let Some(provider) = self.semantics_provider.as_ref() else {
20613            return false;
20614        };
20615
20616        let mut supports = false;
20617        self.buffer().update(cx, |this, cx| {
20618            this.for_each_buffer(|buffer| {
20619                supports |= provider.supports_inlay_hints(buffer, cx);
20620            });
20621        });
20622
20623        supports
20624    }
20625
20626    pub fn is_focused(&self, window: &Window) -> bool {
20627        self.focus_handle.is_focused(window)
20628    }
20629
20630    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20631        cx.emit(EditorEvent::Focused);
20632
20633        if let Some(descendant) = self
20634            .last_focused_descendant
20635            .take()
20636            .and_then(|descendant| descendant.upgrade())
20637        {
20638            window.focus(&descendant);
20639        } else {
20640            if let Some(blame) = self.blame.as_ref() {
20641                blame.update(cx, GitBlame::focus)
20642            }
20643
20644            self.blink_manager.update(cx, BlinkManager::enable);
20645            self.show_cursor_names(window, cx);
20646            self.buffer.update(cx, |buffer, cx| {
20647                buffer.finalize_last_transaction(cx);
20648                if self.leader_id.is_none() {
20649                    buffer.set_active_selections(
20650                        &self.selections.disjoint_anchors(),
20651                        self.selections.line_mode,
20652                        self.cursor_shape,
20653                        cx,
20654                    );
20655                }
20656            });
20657        }
20658    }
20659
20660    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20661        cx.emit(EditorEvent::FocusedIn)
20662    }
20663
20664    fn handle_focus_out(
20665        &mut self,
20666        event: FocusOutEvent,
20667        _window: &mut Window,
20668        cx: &mut Context<Self>,
20669    ) {
20670        if event.blurred != self.focus_handle {
20671            self.last_focused_descendant = Some(event.blurred);
20672        }
20673        self.selection_drag_state = SelectionDragState::None;
20674        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20675    }
20676
20677    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20678        self.blink_manager.update(cx, BlinkManager::disable);
20679        self.buffer
20680            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20681
20682        if let Some(blame) = self.blame.as_ref() {
20683            blame.update(cx, GitBlame::blur)
20684        }
20685        if !self.hover_state.focused(window, cx) {
20686            hide_hover(self, cx);
20687        }
20688        if !self
20689            .context_menu
20690            .borrow()
20691            .as_ref()
20692            .is_some_and(|context_menu| context_menu.focused(window, cx))
20693        {
20694            self.hide_context_menu(window, cx);
20695        }
20696        self.discard_inline_completion(false, cx);
20697        cx.emit(EditorEvent::Blurred);
20698        cx.notify();
20699    }
20700
20701    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20702        let mut pending: String = window
20703            .pending_input_keystrokes()
20704            .into_iter()
20705            .flatten()
20706            .filter_map(|keystroke| {
20707                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20708                    keystroke.key_char.clone()
20709                } else {
20710                    None
20711                }
20712            })
20713            .collect();
20714
20715        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20716            pending = "".to_string();
20717        }
20718
20719        let existing_pending = self
20720            .text_highlights::<PendingInput>(cx)
20721            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20722        if existing_pending.is_none() && pending.is_empty() {
20723            return;
20724        }
20725        let transaction =
20726            self.transact(window, cx, |this, window, cx| {
20727                let selections = this.selections.all::<usize>(cx);
20728                let edits = selections
20729                    .iter()
20730                    .map(|selection| (selection.end..selection.end, pending.clone()));
20731                this.edit(edits, cx);
20732                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20733                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20734                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20735                    }));
20736                });
20737                if let Some(existing_ranges) = existing_pending {
20738                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20739                    this.edit(edits, cx);
20740                }
20741            });
20742
20743        let snapshot = self.snapshot(window, cx);
20744        let ranges = self
20745            .selections
20746            .all::<usize>(cx)
20747            .into_iter()
20748            .map(|selection| {
20749                snapshot.buffer_snapshot.anchor_after(selection.end)
20750                    ..snapshot
20751                        .buffer_snapshot
20752                        .anchor_before(selection.end + pending.len())
20753            })
20754            .collect();
20755
20756        if pending.is_empty() {
20757            self.clear_highlights::<PendingInput>(cx);
20758        } else {
20759            self.highlight_text::<PendingInput>(
20760                ranges,
20761                HighlightStyle {
20762                    underline: Some(UnderlineStyle {
20763                        thickness: px(1.),
20764                        color: None,
20765                        wavy: false,
20766                    }),
20767                    ..Default::default()
20768                },
20769                cx,
20770            );
20771        }
20772
20773        self.ime_transaction = self.ime_transaction.or(transaction);
20774        if let Some(transaction) = self.ime_transaction {
20775            self.buffer.update(cx, |buffer, cx| {
20776                buffer.group_until_transaction(transaction, cx);
20777            });
20778        }
20779
20780        if self.text_highlights::<PendingInput>(cx).is_none() {
20781            self.ime_transaction.take();
20782        }
20783    }
20784
20785    pub fn register_action_renderer(
20786        &mut self,
20787        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20788    ) -> Subscription {
20789        let id = self.next_editor_action_id.post_inc();
20790        self.editor_actions
20791            .borrow_mut()
20792            .insert(id, Box::new(listener));
20793
20794        let editor_actions = self.editor_actions.clone();
20795        Subscription::new(move || {
20796            editor_actions.borrow_mut().remove(&id);
20797        })
20798    }
20799
20800    pub fn register_action<A: Action>(
20801        &mut self,
20802        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20803    ) -> Subscription {
20804        let id = self.next_editor_action_id.post_inc();
20805        let listener = Arc::new(listener);
20806        self.editor_actions.borrow_mut().insert(
20807            id,
20808            Box::new(move |_, window, _| {
20809                let listener = listener.clone();
20810                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20811                    let action = action.downcast_ref().unwrap();
20812                    if phase == DispatchPhase::Bubble {
20813                        listener(action, window, cx)
20814                    }
20815                })
20816            }),
20817        );
20818
20819        let editor_actions = self.editor_actions.clone();
20820        Subscription::new(move || {
20821            editor_actions.borrow_mut().remove(&id);
20822        })
20823    }
20824
20825    pub fn file_header_size(&self) -> u32 {
20826        FILE_HEADER_HEIGHT
20827    }
20828
20829    pub fn restore(
20830        &mut self,
20831        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        let workspace = self.workspace();
20836        let project = self.project.as_ref();
20837        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20838            let mut tasks = Vec::new();
20839            for (buffer_id, changes) in revert_changes {
20840                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20841                    buffer.update(cx, |buffer, cx| {
20842                        buffer.edit(
20843                            changes
20844                                .into_iter()
20845                                .map(|(range, text)| (range, text.to_string())),
20846                            None,
20847                            cx,
20848                        );
20849                    });
20850
20851                    if let Some(project) =
20852                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20853                    {
20854                        project.update(cx, |project, cx| {
20855                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20856                        })
20857                    }
20858                }
20859            }
20860            tasks
20861        });
20862        cx.spawn_in(window, async move |_, cx| {
20863            for (buffer, task) in save_tasks {
20864                let result = task.await;
20865                if result.is_err() {
20866                    let Some(path) = buffer
20867                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20868                        .ok()
20869                    else {
20870                        continue;
20871                    };
20872                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20873                        let Some(task) = cx
20874                            .update_window_entity(&workspace, |workspace, window, cx| {
20875                                workspace
20876                                    .open_path_preview(path, None, false, false, false, window, cx)
20877                            })
20878                            .ok()
20879                        else {
20880                            continue;
20881                        };
20882                        task.await.log_err();
20883                    }
20884                }
20885            }
20886        })
20887        .detach();
20888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20889            selections.refresh()
20890        });
20891    }
20892
20893    pub fn to_pixel_point(
20894        &self,
20895        source: multi_buffer::Anchor,
20896        editor_snapshot: &EditorSnapshot,
20897        window: &mut Window,
20898    ) -> Option<gpui::Point<Pixels>> {
20899        let source_point = source.to_display_point(editor_snapshot);
20900        self.display_to_pixel_point(source_point, editor_snapshot, window)
20901    }
20902
20903    pub fn display_to_pixel_point(
20904        &self,
20905        source: DisplayPoint,
20906        editor_snapshot: &EditorSnapshot,
20907        window: &mut Window,
20908    ) -> Option<gpui::Point<Pixels>> {
20909        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20910        let text_layout_details = self.text_layout_details(window);
20911        let scroll_top = text_layout_details
20912            .scroll_anchor
20913            .scroll_position(editor_snapshot)
20914            .y;
20915
20916        if source.row().as_f32() < scroll_top.floor() {
20917            return None;
20918        }
20919        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20920        let source_y = line_height * (source.row().as_f32() - scroll_top);
20921        Some(gpui::Point::new(source_x, source_y))
20922    }
20923
20924    pub fn has_visible_completions_menu(&self) -> bool {
20925        !self.edit_prediction_preview_is_active()
20926            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20927                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20928            })
20929    }
20930
20931    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20932        if self.mode.is_minimap() {
20933            return;
20934        }
20935        self.addons
20936            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20937    }
20938
20939    pub fn unregister_addon<T: Addon>(&mut self) {
20940        self.addons.remove(&std::any::TypeId::of::<T>());
20941    }
20942
20943    pub fn addon<T: Addon>(&self) -> Option<&T> {
20944        let type_id = std::any::TypeId::of::<T>();
20945        self.addons
20946            .get(&type_id)
20947            .and_then(|item| item.to_any().downcast_ref::<T>())
20948    }
20949
20950    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20951        let type_id = std::any::TypeId::of::<T>();
20952        self.addons
20953            .get_mut(&type_id)
20954            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20955    }
20956
20957    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20958        let text_layout_details = self.text_layout_details(window);
20959        let style = &text_layout_details.editor_style;
20960        let font_id = window.text_system().resolve_font(&style.text.font());
20961        let font_size = style.text.font_size.to_pixels(window.rem_size());
20962        let line_height = style.text.line_height_in_pixels(window.rem_size());
20963        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20964        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20965
20966        CharacterDimensions {
20967            em_width,
20968            em_advance,
20969            line_height,
20970        }
20971    }
20972
20973    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20974        self.load_diff_task.clone()
20975    }
20976
20977    fn read_metadata_from_db(
20978        &mut self,
20979        item_id: u64,
20980        workspace_id: WorkspaceId,
20981        window: &mut Window,
20982        cx: &mut Context<Editor>,
20983    ) {
20984        if self.is_singleton(cx)
20985            && !self.mode.is_minimap()
20986            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20987        {
20988            let buffer_snapshot = OnceCell::new();
20989
20990            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20991                if !folds.is_empty() {
20992                    let snapshot =
20993                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20994                    self.fold_ranges(
20995                        folds
20996                            .into_iter()
20997                            .map(|(start, end)| {
20998                                snapshot.clip_offset(start, Bias::Left)
20999                                    ..snapshot.clip_offset(end, Bias::Right)
21000                            })
21001                            .collect(),
21002                        false,
21003                        window,
21004                        cx,
21005                    );
21006                }
21007            }
21008
21009            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21010                if !selections.is_empty() {
21011                    let snapshot =
21012                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21013                    // skip adding the initial selection to selection history
21014                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21015                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21016                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21017                            snapshot.clip_offset(start, Bias::Left)
21018                                ..snapshot.clip_offset(end, Bias::Right)
21019                        }));
21020                    });
21021                    self.selection_history.mode = SelectionHistoryMode::Normal;
21022                }
21023            };
21024        }
21025
21026        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21027    }
21028
21029    fn update_lsp_data(
21030        &mut self,
21031        ignore_cache: bool,
21032        for_buffer: Option<BufferId>,
21033        window: &mut Window,
21034        cx: &mut Context<'_, Self>,
21035    ) {
21036        self.pull_diagnostics(for_buffer, window, cx);
21037        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21038    }
21039}
21040
21041fn vim_enabled(cx: &App) -> bool {
21042    cx.global::<SettingsStore>()
21043        .raw_user_settings()
21044        .get("vim_mode")
21045        == Some(&serde_json::Value::Bool(true))
21046}
21047
21048fn process_completion_for_edit(
21049    completion: &Completion,
21050    intent: CompletionIntent,
21051    buffer: &Entity<Buffer>,
21052    cursor_position: &text::Anchor,
21053    cx: &mut Context<Editor>,
21054) -> CompletionEdit {
21055    let buffer = buffer.read(cx);
21056    let buffer_snapshot = buffer.snapshot();
21057    let (snippet, new_text) = if completion.is_snippet() {
21058        // Workaround for typescript language server issues so that methods don't expand within
21059        // strings and functions with type expressions. The previous point is used because the query
21060        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21061        let mut snippet_source = completion.new_text.clone();
21062        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21063        previous_point.column = previous_point.column.saturating_sub(1);
21064        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21065            if scope.prefers_label_for_snippet_in_completion() {
21066                if let Some(label) = completion.label() {
21067                    if matches!(
21068                        completion.kind(),
21069                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21070                    ) {
21071                        snippet_source = label;
21072                    }
21073                }
21074            }
21075        }
21076        match Snippet::parse(&snippet_source).log_err() {
21077            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21078            None => (None, completion.new_text.clone()),
21079        }
21080    } else {
21081        (None, completion.new_text.clone())
21082    };
21083
21084    let mut range_to_replace = {
21085        let replace_range = &completion.replace_range;
21086        if let CompletionSource::Lsp {
21087            insert_range: Some(insert_range),
21088            ..
21089        } = &completion.source
21090        {
21091            debug_assert_eq!(
21092                insert_range.start, replace_range.start,
21093                "insert_range and replace_range should start at the same position"
21094            );
21095            debug_assert!(
21096                insert_range
21097                    .start
21098                    .cmp(&cursor_position, &buffer_snapshot)
21099                    .is_le(),
21100                "insert_range should start before or at cursor position"
21101            );
21102            debug_assert!(
21103                replace_range
21104                    .start
21105                    .cmp(&cursor_position, &buffer_snapshot)
21106                    .is_le(),
21107                "replace_range should start before or at cursor position"
21108            );
21109            debug_assert!(
21110                insert_range
21111                    .end
21112                    .cmp(&cursor_position, &buffer_snapshot)
21113                    .is_le(),
21114                "insert_range should end before or at cursor position"
21115            );
21116
21117            let should_replace = match intent {
21118                CompletionIntent::CompleteWithInsert => false,
21119                CompletionIntent::CompleteWithReplace => true,
21120                CompletionIntent::Complete | CompletionIntent::Compose => {
21121                    let insert_mode =
21122                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21123                            .completions
21124                            .lsp_insert_mode;
21125                    match insert_mode {
21126                        LspInsertMode::Insert => false,
21127                        LspInsertMode::Replace => true,
21128                        LspInsertMode::ReplaceSubsequence => {
21129                            let mut text_to_replace = buffer.chars_for_range(
21130                                buffer.anchor_before(replace_range.start)
21131                                    ..buffer.anchor_after(replace_range.end),
21132                            );
21133                            let mut current_needle = text_to_replace.next();
21134                            for haystack_ch in completion.label.text.chars() {
21135                                if let Some(needle_ch) = current_needle {
21136                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21137                                        current_needle = text_to_replace.next();
21138                                    }
21139                                }
21140                            }
21141                            current_needle.is_none()
21142                        }
21143                        LspInsertMode::ReplaceSuffix => {
21144                            if replace_range
21145                                .end
21146                                .cmp(&cursor_position, &buffer_snapshot)
21147                                .is_gt()
21148                            {
21149                                let range_after_cursor = *cursor_position..replace_range.end;
21150                                let text_after_cursor = buffer
21151                                    .text_for_range(
21152                                        buffer.anchor_before(range_after_cursor.start)
21153                                            ..buffer.anchor_after(range_after_cursor.end),
21154                                    )
21155                                    .collect::<String>()
21156                                    .to_ascii_lowercase();
21157                                completion
21158                                    .label
21159                                    .text
21160                                    .to_ascii_lowercase()
21161                                    .ends_with(&text_after_cursor)
21162                            } else {
21163                                true
21164                            }
21165                        }
21166                    }
21167                }
21168            };
21169
21170            if should_replace {
21171                replace_range.clone()
21172            } else {
21173                insert_range.clone()
21174            }
21175        } else {
21176            replace_range.clone()
21177        }
21178    };
21179
21180    if range_to_replace
21181        .end
21182        .cmp(&cursor_position, &buffer_snapshot)
21183        .is_lt()
21184    {
21185        range_to_replace.end = *cursor_position;
21186    }
21187
21188    CompletionEdit {
21189        new_text,
21190        replace_range: range_to_replace.to_offset(&buffer),
21191        snippet,
21192    }
21193}
21194
21195struct CompletionEdit {
21196    new_text: String,
21197    replace_range: Range<usize>,
21198    snippet: Option<Snippet>,
21199}
21200
21201fn insert_extra_newline_brackets(
21202    buffer: &MultiBufferSnapshot,
21203    range: Range<usize>,
21204    language: &language::LanguageScope,
21205) -> bool {
21206    let leading_whitespace_len = buffer
21207        .reversed_chars_at(range.start)
21208        .take_while(|c| c.is_whitespace() && *c != '\n')
21209        .map(|c| c.len_utf8())
21210        .sum::<usize>();
21211    let trailing_whitespace_len = buffer
21212        .chars_at(range.end)
21213        .take_while(|c| c.is_whitespace() && *c != '\n')
21214        .map(|c| c.len_utf8())
21215        .sum::<usize>();
21216    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21217
21218    language.brackets().any(|(pair, enabled)| {
21219        let pair_start = pair.start.trim_end();
21220        let pair_end = pair.end.trim_start();
21221
21222        enabled
21223            && pair.newline
21224            && buffer.contains_str_at(range.end, pair_end)
21225            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21226    })
21227}
21228
21229fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21230    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21231        [(buffer, range, _)] => (*buffer, range.clone()),
21232        _ => return false,
21233    };
21234    let pair = {
21235        let mut result: Option<BracketMatch> = None;
21236
21237        for pair in buffer
21238            .all_bracket_ranges(range.clone())
21239            .filter(move |pair| {
21240                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21241            })
21242        {
21243            let len = pair.close_range.end - pair.open_range.start;
21244
21245            if let Some(existing) = &result {
21246                let existing_len = existing.close_range.end - existing.open_range.start;
21247                if len > existing_len {
21248                    continue;
21249                }
21250            }
21251
21252            result = Some(pair);
21253        }
21254
21255        result
21256    };
21257    let Some(pair) = pair else {
21258        return false;
21259    };
21260    pair.newline_only
21261        && buffer
21262            .chars_for_range(pair.open_range.end..range.start)
21263            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21264            .all(|c| c.is_whitespace() && c != '\n')
21265}
21266
21267fn update_uncommitted_diff_for_buffer(
21268    editor: Entity<Editor>,
21269    project: &Entity<Project>,
21270    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21271    buffer: Entity<MultiBuffer>,
21272    cx: &mut App,
21273) -> Task<()> {
21274    let mut tasks = Vec::new();
21275    project.update(cx, |project, cx| {
21276        for buffer in buffers {
21277            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21278                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21279            }
21280        }
21281    });
21282    cx.spawn(async move |cx| {
21283        let diffs = future::join_all(tasks).await;
21284        if editor
21285            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21286            .unwrap_or(false)
21287        {
21288            return;
21289        }
21290
21291        buffer
21292            .update(cx, |buffer, cx| {
21293                for diff in diffs.into_iter().flatten() {
21294                    buffer.add_diff(diff, cx);
21295                }
21296            })
21297            .ok();
21298    })
21299}
21300
21301fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21302    let tab_size = tab_size.get() as usize;
21303    let mut width = offset;
21304
21305    for ch in text.chars() {
21306        width += if ch == '\t' {
21307            tab_size - (width % tab_size)
21308        } else {
21309            1
21310        };
21311    }
21312
21313    width - offset
21314}
21315
21316#[cfg(test)]
21317mod tests {
21318    use super::*;
21319
21320    #[test]
21321    fn test_string_size_with_expanded_tabs() {
21322        let nz = |val| NonZeroU32::new(val).unwrap();
21323        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21324        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21325        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21326        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21327        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21328        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21329        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21330        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21331    }
21332}
21333
21334/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21335struct WordBreakingTokenizer<'a> {
21336    input: &'a str,
21337}
21338
21339impl<'a> WordBreakingTokenizer<'a> {
21340    fn new(input: &'a str) -> Self {
21341        Self { input }
21342    }
21343}
21344
21345fn is_char_ideographic(ch: char) -> bool {
21346    use unicode_script::Script::*;
21347    use unicode_script::UnicodeScript;
21348    matches!(ch.script(), Han | Tangut | Yi)
21349}
21350
21351fn is_grapheme_ideographic(text: &str) -> bool {
21352    text.chars().any(is_char_ideographic)
21353}
21354
21355fn is_grapheme_whitespace(text: &str) -> bool {
21356    text.chars().any(|x| x.is_whitespace())
21357}
21358
21359fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21360    text.chars().next().map_or(false, |ch| {
21361        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21362    })
21363}
21364
21365#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21366enum WordBreakToken<'a> {
21367    Word { token: &'a str, grapheme_len: usize },
21368    InlineWhitespace { token: &'a str, grapheme_len: usize },
21369    Newline,
21370}
21371
21372impl<'a> Iterator for WordBreakingTokenizer<'a> {
21373    /// Yields a span, the count of graphemes in the token, and whether it was
21374    /// whitespace. Note that it also breaks at word boundaries.
21375    type Item = WordBreakToken<'a>;
21376
21377    fn next(&mut self) -> Option<Self::Item> {
21378        use unicode_segmentation::UnicodeSegmentation;
21379        if self.input.is_empty() {
21380            return None;
21381        }
21382
21383        let mut iter = self.input.graphemes(true).peekable();
21384        let mut offset = 0;
21385        let mut grapheme_len = 0;
21386        if let Some(first_grapheme) = iter.next() {
21387            let is_newline = first_grapheme == "\n";
21388            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21389            offset += first_grapheme.len();
21390            grapheme_len += 1;
21391            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21392                if let Some(grapheme) = iter.peek().copied() {
21393                    if should_stay_with_preceding_ideograph(grapheme) {
21394                        offset += grapheme.len();
21395                        grapheme_len += 1;
21396                    }
21397                }
21398            } else {
21399                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21400                let mut next_word_bound = words.peek().copied();
21401                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21402                    next_word_bound = words.next();
21403                }
21404                while let Some(grapheme) = iter.peek().copied() {
21405                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21406                        break;
21407                    };
21408                    if is_grapheme_whitespace(grapheme) != is_whitespace
21409                        || (grapheme == "\n") != is_newline
21410                    {
21411                        break;
21412                    };
21413                    offset += grapheme.len();
21414                    grapheme_len += 1;
21415                    iter.next();
21416                }
21417            }
21418            let token = &self.input[..offset];
21419            self.input = &self.input[offset..];
21420            if token == "\n" {
21421                Some(WordBreakToken::Newline)
21422            } else if is_whitespace {
21423                Some(WordBreakToken::InlineWhitespace {
21424                    token,
21425                    grapheme_len,
21426                })
21427            } else {
21428                Some(WordBreakToken::Word {
21429                    token,
21430                    grapheme_len,
21431                })
21432            }
21433        } else {
21434            None
21435        }
21436    }
21437}
21438
21439#[test]
21440fn test_word_breaking_tokenizer() {
21441    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21442        ("", &[]),
21443        ("  ", &[whitespace("  ", 2)]),
21444        ("Ʒ", &[word("Ʒ", 1)]),
21445        ("Ǽ", &[word("Ǽ", 1)]),
21446        ("", &[word("", 1)]),
21447        ("⋑⋑", &[word("⋑⋑", 2)]),
21448        (
21449            "原理,进而",
21450            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21451        ),
21452        (
21453            "hello world",
21454            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21455        ),
21456        (
21457            "hello, world",
21458            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21459        ),
21460        (
21461            "  hello world",
21462            &[
21463                whitespace("  ", 2),
21464                word("hello", 5),
21465                whitespace(" ", 1),
21466                word("world", 5),
21467            ],
21468        ),
21469        (
21470            "这是什么 \n 钢笔",
21471            &[
21472                word("", 1),
21473                word("", 1),
21474                word("", 1),
21475                word("", 1),
21476                whitespace(" ", 1),
21477                newline(),
21478                whitespace(" ", 1),
21479                word("", 1),
21480                word("", 1),
21481            ],
21482        ),
21483        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21484    ];
21485
21486    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21487        WordBreakToken::Word {
21488            token,
21489            grapheme_len,
21490        }
21491    }
21492
21493    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21494        WordBreakToken::InlineWhitespace {
21495            token,
21496            grapheme_len,
21497        }
21498    }
21499
21500    fn newline() -> WordBreakToken<'static> {
21501        WordBreakToken::Newline
21502    }
21503
21504    for (input, result) in tests {
21505        assert_eq!(
21506            WordBreakingTokenizer::new(input)
21507                .collect::<Vec<_>>()
21508                .as_slice(),
21509            *result,
21510        );
21511    }
21512}
21513
21514fn wrap_with_prefix(
21515    first_line_prefix: String,
21516    subsequent_lines_prefix: String,
21517    unwrapped_text: String,
21518    wrap_column: usize,
21519    tab_size: NonZeroU32,
21520    preserve_existing_whitespace: bool,
21521) -> String {
21522    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21523    let subsequent_lines_prefix_len =
21524        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21525    let mut wrapped_text = String::new();
21526    let mut current_line = first_line_prefix.clone();
21527    let mut is_first_line = true;
21528
21529    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21530    let mut current_line_len = first_line_prefix_len;
21531    let mut in_whitespace = false;
21532    for token in tokenizer {
21533        let have_preceding_whitespace = in_whitespace;
21534        match token {
21535            WordBreakToken::Word {
21536                token,
21537                grapheme_len,
21538            } => {
21539                in_whitespace = false;
21540                let current_prefix_len = if is_first_line {
21541                    first_line_prefix_len
21542                } else {
21543                    subsequent_lines_prefix_len
21544                };
21545                if current_line_len + grapheme_len > wrap_column
21546                    && current_line_len != current_prefix_len
21547                {
21548                    wrapped_text.push_str(current_line.trim_end());
21549                    wrapped_text.push('\n');
21550                    is_first_line = false;
21551                    current_line = subsequent_lines_prefix.clone();
21552                    current_line_len = subsequent_lines_prefix_len;
21553                }
21554                current_line.push_str(token);
21555                current_line_len += grapheme_len;
21556            }
21557            WordBreakToken::InlineWhitespace {
21558                mut token,
21559                mut grapheme_len,
21560            } => {
21561                in_whitespace = true;
21562                if have_preceding_whitespace && !preserve_existing_whitespace {
21563                    continue;
21564                }
21565                if !preserve_existing_whitespace {
21566                    token = " ";
21567                    grapheme_len = 1;
21568                }
21569                let current_prefix_len = if is_first_line {
21570                    first_line_prefix_len
21571                } else {
21572                    subsequent_lines_prefix_len
21573                };
21574                if current_line_len + grapheme_len > wrap_column {
21575                    wrapped_text.push_str(current_line.trim_end());
21576                    wrapped_text.push('\n');
21577                    is_first_line = false;
21578                    current_line = subsequent_lines_prefix.clone();
21579                    current_line_len = subsequent_lines_prefix_len;
21580                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21581                    current_line.push_str(token);
21582                    current_line_len += grapheme_len;
21583                }
21584            }
21585            WordBreakToken::Newline => {
21586                in_whitespace = true;
21587                let current_prefix_len = if is_first_line {
21588                    first_line_prefix_len
21589                } else {
21590                    subsequent_lines_prefix_len
21591                };
21592                if preserve_existing_whitespace {
21593                    wrapped_text.push_str(current_line.trim_end());
21594                    wrapped_text.push('\n');
21595                    is_first_line = false;
21596                    current_line = subsequent_lines_prefix.clone();
21597                    current_line_len = subsequent_lines_prefix_len;
21598                } else if have_preceding_whitespace {
21599                    continue;
21600                } else if current_line_len + 1 > wrap_column
21601                    && current_line_len != current_prefix_len
21602                {
21603                    wrapped_text.push_str(current_line.trim_end());
21604                    wrapped_text.push('\n');
21605                    is_first_line = false;
21606                    current_line = subsequent_lines_prefix.clone();
21607                    current_line_len = subsequent_lines_prefix_len;
21608                } else if current_line_len != current_prefix_len {
21609                    current_line.push(' ');
21610                    current_line_len += 1;
21611                }
21612            }
21613        }
21614    }
21615
21616    if !current_line.is_empty() {
21617        wrapped_text.push_str(&current_line);
21618    }
21619    wrapped_text
21620}
21621
21622#[test]
21623fn test_wrap_with_prefix() {
21624    assert_eq!(
21625        wrap_with_prefix(
21626            "# ".to_string(),
21627            "# ".to_string(),
21628            "abcdefg".to_string(),
21629            4,
21630            NonZeroU32::new(4).unwrap(),
21631            false,
21632        ),
21633        "# abcdefg"
21634    );
21635    assert_eq!(
21636        wrap_with_prefix(
21637            "".to_string(),
21638            "".to_string(),
21639            "\thello world".to_string(),
21640            8,
21641            NonZeroU32::new(4).unwrap(),
21642            false,
21643        ),
21644        "hello\nworld"
21645    );
21646    assert_eq!(
21647        wrap_with_prefix(
21648            "// ".to_string(),
21649            "// ".to_string(),
21650            "xx \nyy zz aa bb cc".to_string(),
21651            12,
21652            NonZeroU32::new(4).unwrap(),
21653            false,
21654        ),
21655        "// xx yy zz\n// aa bb cc"
21656    );
21657    assert_eq!(
21658        wrap_with_prefix(
21659            String::new(),
21660            String::new(),
21661            "这是什么 \n 钢笔".to_string(),
21662            3,
21663            NonZeroU32::new(4).unwrap(),
21664            false,
21665        ),
21666        "这是什\n么 钢\n"
21667    );
21668}
21669
21670pub trait CollaborationHub {
21671    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21672    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21673    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21674}
21675
21676impl CollaborationHub for Entity<Project> {
21677    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21678        self.read(cx).collaborators()
21679    }
21680
21681    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21682        self.read(cx).user_store().read(cx).participant_indices()
21683    }
21684
21685    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21686        let this = self.read(cx);
21687        let user_ids = this.collaborators().values().map(|c| c.user_id);
21688        this.user_store().read(cx).participant_names(user_ids, cx)
21689    }
21690}
21691
21692pub trait SemanticsProvider {
21693    fn hover(
21694        &self,
21695        buffer: &Entity<Buffer>,
21696        position: text::Anchor,
21697        cx: &mut App,
21698    ) -> Option<Task<Vec<project::Hover>>>;
21699
21700    fn inline_values(
21701        &self,
21702        buffer_handle: Entity<Buffer>,
21703        range: Range<text::Anchor>,
21704        cx: &mut App,
21705    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21706
21707    fn inlay_hints(
21708        &self,
21709        buffer_handle: Entity<Buffer>,
21710        range: Range<text::Anchor>,
21711        cx: &mut App,
21712    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21713
21714    fn resolve_inlay_hint(
21715        &self,
21716        hint: InlayHint,
21717        buffer_handle: Entity<Buffer>,
21718        server_id: LanguageServerId,
21719        cx: &mut App,
21720    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21721
21722    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21723
21724    fn document_highlights(
21725        &self,
21726        buffer: &Entity<Buffer>,
21727        position: text::Anchor,
21728        cx: &mut App,
21729    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21730
21731    fn definitions(
21732        &self,
21733        buffer: &Entity<Buffer>,
21734        position: text::Anchor,
21735        kind: GotoDefinitionKind,
21736        cx: &mut App,
21737    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21738
21739    fn range_for_rename(
21740        &self,
21741        buffer: &Entity<Buffer>,
21742        position: text::Anchor,
21743        cx: &mut App,
21744    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21745
21746    fn perform_rename(
21747        &self,
21748        buffer: &Entity<Buffer>,
21749        position: text::Anchor,
21750        new_name: String,
21751        cx: &mut App,
21752    ) -> Option<Task<Result<ProjectTransaction>>>;
21753}
21754
21755pub trait CompletionProvider {
21756    fn completions(
21757        &self,
21758        excerpt_id: ExcerptId,
21759        buffer: &Entity<Buffer>,
21760        buffer_position: text::Anchor,
21761        trigger: CompletionContext,
21762        window: &mut Window,
21763        cx: &mut Context<Editor>,
21764    ) -> Task<Result<Vec<CompletionResponse>>>;
21765
21766    fn resolve_completions(
21767        &self,
21768        _buffer: Entity<Buffer>,
21769        _completion_indices: Vec<usize>,
21770        _completions: Rc<RefCell<Box<[Completion]>>>,
21771        _cx: &mut Context<Editor>,
21772    ) -> Task<Result<bool>> {
21773        Task::ready(Ok(false))
21774    }
21775
21776    fn apply_additional_edits_for_completion(
21777        &self,
21778        _buffer: Entity<Buffer>,
21779        _completions: Rc<RefCell<Box<[Completion]>>>,
21780        _completion_index: usize,
21781        _push_to_history: bool,
21782        _cx: &mut Context<Editor>,
21783    ) -> Task<Result<Option<language::Transaction>>> {
21784        Task::ready(Ok(None))
21785    }
21786
21787    fn is_completion_trigger(
21788        &self,
21789        buffer: &Entity<Buffer>,
21790        position: language::Anchor,
21791        text: &str,
21792        trigger_in_words: bool,
21793        menu_is_open: bool,
21794        cx: &mut Context<Editor>,
21795    ) -> bool;
21796
21797    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21798
21799    fn sort_completions(&self) -> bool {
21800        true
21801    }
21802
21803    fn filter_completions(&self) -> bool {
21804        true
21805    }
21806}
21807
21808pub trait CodeActionProvider {
21809    fn id(&self) -> Arc<str>;
21810
21811    fn code_actions(
21812        &self,
21813        buffer: &Entity<Buffer>,
21814        range: Range<text::Anchor>,
21815        window: &mut Window,
21816        cx: &mut App,
21817    ) -> Task<Result<Vec<CodeAction>>>;
21818
21819    fn apply_code_action(
21820        &self,
21821        buffer_handle: Entity<Buffer>,
21822        action: CodeAction,
21823        excerpt_id: ExcerptId,
21824        push_to_history: bool,
21825        window: &mut Window,
21826        cx: &mut App,
21827    ) -> Task<Result<ProjectTransaction>>;
21828}
21829
21830impl CodeActionProvider for Entity<Project> {
21831    fn id(&self) -> Arc<str> {
21832        "project".into()
21833    }
21834
21835    fn code_actions(
21836        &self,
21837        buffer: &Entity<Buffer>,
21838        range: Range<text::Anchor>,
21839        _window: &mut Window,
21840        cx: &mut App,
21841    ) -> Task<Result<Vec<CodeAction>>> {
21842        self.update(cx, |project, cx| {
21843            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21844            let code_actions = project.code_actions(buffer, range, None, cx);
21845            cx.background_spawn(async move {
21846                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21847                Ok(code_lens_actions
21848                    .context("code lens fetch")?
21849                    .into_iter()
21850                    .chain(code_actions.context("code action fetch")?)
21851                    .collect())
21852            })
21853        })
21854    }
21855
21856    fn apply_code_action(
21857        &self,
21858        buffer_handle: Entity<Buffer>,
21859        action: CodeAction,
21860        _excerpt_id: ExcerptId,
21861        push_to_history: bool,
21862        _window: &mut Window,
21863        cx: &mut App,
21864    ) -> Task<Result<ProjectTransaction>> {
21865        self.update(cx, |project, cx| {
21866            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21867        })
21868    }
21869}
21870
21871fn snippet_completions(
21872    project: &Project,
21873    buffer: &Entity<Buffer>,
21874    buffer_position: text::Anchor,
21875    cx: &mut App,
21876) -> Task<Result<CompletionResponse>> {
21877    let languages = buffer.read(cx).languages_at(buffer_position);
21878    let snippet_store = project.snippets().read(cx);
21879
21880    let scopes: Vec<_> = languages
21881        .iter()
21882        .filter_map(|language| {
21883            let language_name = language.lsp_id();
21884            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21885
21886            if snippets.is_empty() {
21887                None
21888            } else {
21889                Some((language.default_scope(), snippets))
21890            }
21891        })
21892        .collect();
21893
21894    if scopes.is_empty() {
21895        return Task::ready(Ok(CompletionResponse {
21896            completions: vec![],
21897            is_incomplete: false,
21898        }));
21899    }
21900
21901    let snapshot = buffer.read(cx).text_snapshot();
21902    let chars: String = snapshot
21903        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21904        .collect();
21905    let executor = cx.background_executor().clone();
21906
21907    cx.background_spawn(async move {
21908        let mut is_incomplete = false;
21909        let mut completions: Vec<Completion> = Vec::new();
21910        for (scope, snippets) in scopes.into_iter() {
21911            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21912            let mut last_word = chars
21913                .chars()
21914                .take_while(|c| classifier.is_word(*c))
21915                .collect::<String>();
21916            last_word = last_word.chars().rev().collect();
21917
21918            if last_word.is_empty() {
21919                return Ok(CompletionResponse {
21920                    completions: vec![],
21921                    is_incomplete: true,
21922                });
21923            }
21924
21925            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21926            let to_lsp = |point: &text::Anchor| {
21927                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21928                point_to_lsp(end)
21929            };
21930            let lsp_end = to_lsp(&buffer_position);
21931
21932            let candidates = snippets
21933                .iter()
21934                .enumerate()
21935                .flat_map(|(ix, snippet)| {
21936                    snippet
21937                        .prefix
21938                        .iter()
21939                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21940                })
21941                .collect::<Vec<StringMatchCandidate>>();
21942
21943            const MAX_RESULTS: usize = 100;
21944            let mut matches = fuzzy::match_strings(
21945                &candidates,
21946                &last_word,
21947                last_word.chars().any(|c| c.is_uppercase()),
21948                true,
21949                MAX_RESULTS,
21950                &Default::default(),
21951                executor.clone(),
21952            )
21953            .await;
21954
21955            if matches.len() >= MAX_RESULTS {
21956                is_incomplete = true;
21957            }
21958
21959            // Remove all candidates where the query's start does not match the start of any word in the candidate
21960            if let Some(query_start) = last_word.chars().next() {
21961                matches.retain(|string_match| {
21962                    split_words(&string_match.string).any(|word| {
21963                        // Check that the first codepoint of the word as lowercase matches the first
21964                        // codepoint of the query as lowercase
21965                        word.chars()
21966                            .flat_map(|codepoint| codepoint.to_lowercase())
21967                            .zip(query_start.to_lowercase())
21968                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21969                    })
21970                });
21971            }
21972
21973            let matched_strings = matches
21974                .into_iter()
21975                .map(|m| m.string)
21976                .collect::<HashSet<_>>();
21977
21978            completions.extend(snippets.iter().filter_map(|snippet| {
21979                let matching_prefix = snippet
21980                    .prefix
21981                    .iter()
21982                    .find(|prefix| matched_strings.contains(*prefix))?;
21983                let start = as_offset - last_word.len();
21984                let start = snapshot.anchor_before(start);
21985                let range = start..buffer_position;
21986                let lsp_start = to_lsp(&start);
21987                let lsp_range = lsp::Range {
21988                    start: lsp_start,
21989                    end: lsp_end,
21990                };
21991                Some(Completion {
21992                    replace_range: range,
21993                    new_text: snippet.body.clone(),
21994                    source: CompletionSource::Lsp {
21995                        insert_range: None,
21996                        server_id: LanguageServerId(usize::MAX),
21997                        resolved: true,
21998                        lsp_completion: Box::new(lsp::CompletionItem {
21999                            label: snippet.prefix.first().unwrap().clone(),
22000                            kind: Some(CompletionItemKind::SNIPPET),
22001                            label_details: snippet.description.as_ref().map(|description| {
22002                                lsp::CompletionItemLabelDetails {
22003                                    detail: Some(description.clone()),
22004                                    description: None,
22005                                }
22006                            }),
22007                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22008                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22009                                lsp::InsertReplaceEdit {
22010                                    new_text: snippet.body.clone(),
22011                                    insert: lsp_range,
22012                                    replace: lsp_range,
22013                                },
22014                            )),
22015                            filter_text: Some(snippet.body.clone()),
22016                            sort_text: Some(char::MAX.to_string()),
22017                            ..lsp::CompletionItem::default()
22018                        }),
22019                        lsp_defaults: None,
22020                    },
22021                    label: CodeLabel {
22022                        text: matching_prefix.clone(),
22023                        runs: Vec::new(),
22024                        filter_range: 0..matching_prefix.len(),
22025                    },
22026                    icon_path: None,
22027                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22028                        single_line: snippet.name.clone().into(),
22029                        plain_text: snippet
22030                            .description
22031                            .clone()
22032                            .map(|description| description.into()),
22033                    }),
22034                    insert_text_mode: None,
22035                    confirm: None,
22036                })
22037            }))
22038        }
22039
22040        Ok(CompletionResponse {
22041            completions,
22042            is_incomplete,
22043        })
22044    })
22045}
22046
22047impl CompletionProvider for Entity<Project> {
22048    fn completions(
22049        &self,
22050        _excerpt_id: ExcerptId,
22051        buffer: &Entity<Buffer>,
22052        buffer_position: text::Anchor,
22053        options: CompletionContext,
22054        _window: &mut Window,
22055        cx: &mut Context<Editor>,
22056    ) -> Task<Result<Vec<CompletionResponse>>> {
22057        self.update(cx, |project, cx| {
22058            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22059            let project_completions = project.completions(buffer, buffer_position, options, cx);
22060            cx.background_spawn(async move {
22061                let mut responses = project_completions.await?;
22062                let snippets = snippets.await?;
22063                if !snippets.completions.is_empty() {
22064                    responses.push(snippets);
22065                }
22066                Ok(responses)
22067            })
22068        })
22069    }
22070
22071    fn resolve_completions(
22072        &self,
22073        buffer: Entity<Buffer>,
22074        completion_indices: Vec<usize>,
22075        completions: Rc<RefCell<Box<[Completion]>>>,
22076        cx: &mut Context<Editor>,
22077    ) -> Task<Result<bool>> {
22078        self.update(cx, |project, cx| {
22079            project.lsp_store().update(cx, |lsp_store, cx| {
22080                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22081            })
22082        })
22083    }
22084
22085    fn apply_additional_edits_for_completion(
22086        &self,
22087        buffer: Entity<Buffer>,
22088        completions: Rc<RefCell<Box<[Completion]>>>,
22089        completion_index: usize,
22090        push_to_history: bool,
22091        cx: &mut Context<Editor>,
22092    ) -> Task<Result<Option<language::Transaction>>> {
22093        self.update(cx, |project, cx| {
22094            project.lsp_store().update(cx, |lsp_store, cx| {
22095                lsp_store.apply_additional_edits_for_completion(
22096                    buffer,
22097                    completions,
22098                    completion_index,
22099                    push_to_history,
22100                    cx,
22101                )
22102            })
22103        })
22104    }
22105
22106    fn is_completion_trigger(
22107        &self,
22108        buffer: &Entity<Buffer>,
22109        position: language::Anchor,
22110        text: &str,
22111        trigger_in_words: bool,
22112        menu_is_open: bool,
22113        cx: &mut Context<Editor>,
22114    ) -> bool {
22115        let mut chars = text.chars();
22116        let char = if let Some(char) = chars.next() {
22117            char
22118        } else {
22119            return false;
22120        };
22121        if chars.next().is_some() {
22122            return false;
22123        }
22124
22125        let buffer = buffer.read(cx);
22126        let snapshot = buffer.snapshot();
22127        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22128            return false;
22129        }
22130        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22131        if trigger_in_words && classifier.is_word(char) {
22132            return true;
22133        }
22134
22135        buffer.completion_triggers().contains(text)
22136    }
22137}
22138
22139impl SemanticsProvider for Entity<Project> {
22140    fn hover(
22141        &self,
22142        buffer: &Entity<Buffer>,
22143        position: text::Anchor,
22144        cx: &mut App,
22145    ) -> Option<Task<Vec<project::Hover>>> {
22146        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22147    }
22148
22149    fn document_highlights(
22150        &self,
22151        buffer: &Entity<Buffer>,
22152        position: text::Anchor,
22153        cx: &mut App,
22154    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22155        Some(self.update(cx, |project, cx| {
22156            project.document_highlights(buffer, position, cx)
22157        }))
22158    }
22159
22160    fn definitions(
22161        &self,
22162        buffer: &Entity<Buffer>,
22163        position: text::Anchor,
22164        kind: GotoDefinitionKind,
22165        cx: &mut App,
22166    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22167        Some(self.update(cx, |project, cx| match kind {
22168            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22169            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22170            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22171            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22172        }))
22173    }
22174
22175    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22176        // TODO: make this work for remote projects
22177        self.update(cx, |project, cx| {
22178            if project
22179                .active_debug_session(cx)
22180                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22181            {
22182                return true;
22183            }
22184
22185            buffer.update(cx, |buffer, cx| {
22186                project.any_language_server_supports_inlay_hints(buffer, cx)
22187            })
22188        })
22189    }
22190
22191    fn inline_values(
22192        &self,
22193        buffer_handle: Entity<Buffer>,
22194        range: Range<text::Anchor>,
22195        cx: &mut App,
22196    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22197        self.update(cx, |project, cx| {
22198            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22199
22200            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22201        })
22202    }
22203
22204    fn inlay_hints(
22205        &self,
22206        buffer_handle: Entity<Buffer>,
22207        range: Range<text::Anchor>,
22208        cx: &mut App,
22209    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22210        Some(self.update(cx, |project, cx| {
22211            project.inlay_hints(buffer_handle, range, cx)
22212        }))
22213    }
22214
22215    fn resolve_inlay_hint(
22216        &self,
22217        hint: InlayHint,
22218        buffer_handle: Entity<Buffer>,
22219        server_id: LanguageServerId,
22220        cx: &mut App,
22221    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22222        Some(self.update(cx, |project, cx| {
22223            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22224        }))
22225    }
22226
22227    fn range_for_rename(
22228        &self,
22229        buffer: &Entity<Buffer>,
22230        position: text::Anchor,
22231        cx: &mut App,
22232    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22233        Some(self.update(cx, |project, cx| {
22234            let buffer = buffer.clone();
22235            let task = project.prepare_rename(buffer.clone(), position, cx);
22236            cx.spawn(async move |_, cx| {
22237                Ok(match task.await? {
22238                    PrepareRenameResponse::Success(range) => Some(range),
22239                    PrepareRenameResponse::InvalidPosition => None,
22240                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22241                        // Fallback on using TreeSitter info to determine identifier range
22242                        buffer.read_with(cx, |buffer, _| {
22243                            let snapshot = buffer.snapshot();
22244                            let (range, kind) = snapshot.surrounding_word(position, false);
22245                            if kind != Some(CharKind::Word) {
22246                                return None;
22247                            }
22248                            Some(
22249                                snapshot.anchor_before(range.start)
22250                                    ..snapshot.anchor_after(range.end),
22251                            )
22252                        })?
22253                    }
22254                })
22255            })
22256        }))
22257    }
22258
22259    fn perform_rename(
22260        &self,
22261        buffer: &Entity<Buffer>,
22262        position: text::Anchor,
22263        new_name: String,
22264        cx: &mut App,
22265    ) -> Option<Task<Result<ProjectTransaction>>> {
22266        Some(self.update(cx, |project, cx| {
22267            project.perform_rename(buffer.clone(), position, new_name, cx)
22268        }))
22269    }
22270}
22271
22272fn inlay_hint_settings(
22273    location: Anchor,
22274    snapshot: &MultiBufferSnapshot,
22275    cx: &mut Context<Editor>,
22276) -> InlayHintSettings {
22277    let file = snapshot.file_at(location);
22278    let language = snapshot.language_at(location).map(|l| l.name());
22279    language_settings(language, file, cx).inlay_hints
22280}
22281
22282fn consume_contiguous_rows(
22283    contiguous_row_selections: &mut Vec<Selection<Point>>,
22284    selection: &Selection<Point>,
22285    display_map: &DisplaySnapshot,
22286    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22287) -> (MultiBufferRow, MultiBufferRow) {
22288    contiguous_row_selections.push(selection.clone());
22289    let start_row = MultiBufferRow(selection.start.row);
22290    let mut end_row = ending_row(selection, display_map);
22291
22292    while let Some(next_selection) = selections.peek() {
22293        if next_selection.start.row <= end_row.0 {
22294            end_row = ending_row(next_selection, display_map);
22295            contiguous_row_selections.push(selections.next().unwrap().clone());
22296        } else {
22297            break;
22298        }
22299    }
22300    (start_row, end_row)
22301}
22302
22303fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22304    if next_selection.end.column > 0 || next_selection.is_empty() {
22305        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22306    } else {
22307        MultiBufferRow(next_selection.end.row)
22308    }
22309}
22310
22311impl EditorSnapshot {
22312    pub fn remote_selections_in_range<'a>(
22313        &'a self,
22314        range: &'a Range<Anchor>,
22315        collaboration_hub: &dyn CollaborationHub,
22316        cx: &'a App,
22317    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22318        let participant_names = collaboration_hub.user_names(cx);
22319        let participant_indices = collaboration_hub.user_participant_indices(cx);
22320        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22321        let collaborators_by_replica_id = collaborators_by_peer_id
22322            .values()
22323            .map(|collaborator| (collaborator.replica_id, collaborator))
22324            .collect::<HashMap<_, _>>();
22325        self.buffer_snapshot
22326            .selections_in_range(range, false)
22327            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22328                if replica_id == AGENT_REPLICA_ID {
22329                    Some(RemoteSelection {
22330                        replica_id,
22331                        selection,
22332                        cursor_shape,
22333                        line_mode,
22334                        collaborator_id: CollaboratorId::Agent,
22335                        user_name: Some("Agent".into()),
22336                        color: cx.theme().players().agent(),
22337                    })
22338                } else {
22339                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22340                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22341                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22342                    Some(RemoteSelection {
22343                        replica_id,
22344                        selection,
22345                        cursor_shape,
22346                        line_mode,
22347                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22348                        user_name,
22349                        color: if let Some(index) = participant_index {
22350                            cx.theme().players().color_for_participant(index.0)
22351                        } else {
22352                            cx.theme().players().absent()
22353                        },
22354                    })
22355                }
22356            })
22357    }
22358
22359    pub fn hunks_for_ranges(
22360        &self,
22361        ranges: impl IntoIterator<Item = Range<Point>>,
22362    ) -> Vec<MultiBufferDiffHunk> {
22363        let mut hunks = Vec::new();
22364        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22365            HashMap::default();
22366        for query_range in ranges {
22367            let query_rows =
22368                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22369            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22370                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22371            ) {
22372                // Include deleted hunks that are adjacent to the query range, because
22373                // otherwise they would be missed.
22374                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22375                if hunk.status().is_deleted() {
22376                    intersects_range |= hunk.row_range.start == query_rows.end;
22377                    intersects_range |= hunk.row_range.end == query_rows.start;
22378                }
22379                if intersects_range {
22380                    if !processed_buffer_rows
22381                        .entry(hunk.buffer_id)
22382                        .or_default()
22383                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22384                    {
22385                        continue;
22386                    }
22387                    hunks.push(hunk);
22388                }
22389            }
22390        }
22391
22392        hunks
22393    }
22394
22395    fn display_diff_hunks_for_rows<'a>(
22396        &'a self,
22397        display_rows: Range<DisplayRow>,
22398        folded_buffers: &'a HashSet<BufferId>,
22399    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22400        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22401        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22402
22403        self.buffer_snapshot
22404            .diff_hunks_in_range(buffer_start..buffer_end)
22405            .filter_map(|hunk| {
22406                if folded_buffers.contains(&hunk.buffer_id) {
22407                    return None;
22408                }
22409
22410                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22411                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22412
22413                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22414                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22415
22416                let display_hunk = if hunk_display_start.column() != 0 {
22417                    DisplayDiffHunk::Folded {
22418                        display_row: hunk_display_start.row(),
22419                    }
22420                } else {
22421                    let mut end_row = hunk_display_end.row();
22422                    if hunk_display_end.column() > 0 {
22423                        end_row.0 += 1;
22424                    }
22425                    let is_created_file = hunk.is_created_file();
22426                    DisplayDiffHunk::Unfolded {
22427                        status: hunk.status(),
22428                        diff_base_byte_range: hunk.diff_base_byte_range,
22429                        display_row_range: hunk_display_start.row()..end_row,
22430                        multi_buffer_range: Anchor::range_in_buffer(
22431                            hunk.excerpt_id,
22432                            hunk.buffer_id,
22433                            hunk.buffer_range,
22434                        ),
22435                        is_created_file,
22436                    }
22437                };
22438
22439                Some(display_hunk)
22440            })
22441    }
22442
22443    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22444        self.display_snapshot.buffer_snapshot.language_at(position)
22445    }
22446
22447    pub fn is_focused(&self) -> bool {
22448        self.is_focused
22449    }
22450
22451    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22452        self.placeholder_text.as_ref()
22453    }
22454
22455    pub fn scroll_position(&self) -> gpui::Point<f32> {
22456        self.scroll_anchor.scroll_position(&self.display_snapshot)
22457    }
22458
22459    fn gutter_dimensions(
22460        &self,
22461        font_id: FontId,
22462        font_size: Pixels,
22463        max_line_number_width: Pixels,
22464        cx: &App,
22465    ) -> Option<GutterDimensions> {
22466        if !self.show_gutter {
22467            return None;
22468        }
22469
22470        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22471        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22472
22473        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22474            matches!(
22475                ProjectSettings::get_global(cx).git.git_gutter,
22476                Some(GitGutterSetting::TrackedFiles)
22477            )
22478        });
22479        let gutter_settings = EditorSettings::get_global(cx).gutter;
22480        let show_line_numbers = self
22481            .show_line_numbers
22482            .unwrap_or(gutter_settings.line_numbers);
22483        let line_gutter_width = if show_line_numbers {
22484            // Avoid flicker-like gutter resizes when the line number gains another digit by
22485            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22486            let min_width_for_number_on_gutter =
22487                ch_advance * gutter_settings.min_line_number_digits as f32;
22488            max_line_number_width.max(min_width_for_number_on_gutter)
22489        } else {
22490            0.0.into()
22491        };
22492
22493        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22494        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22495
22496        let git_blame_entries_width =
22497            self.git_blame_gutter_max_author_length
22498                .map(|max_author_length| {
22499                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22500                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22501
22502                    /// The number of characters to dedicate to gaps and margins.
22503                    const SPACING_WIDTH: usize = 4;
22504
22505                    let max_char_count = max_author_length.min(renderer.max_author_length())
22506                        + ::git::SHORT_SHA_LENGTH
22507                        + MAX_RELATIVE_TIMESTAMP.len()
22508                        + SPACING_WIDTH;
22509
22510                    ch_advance * max_char_count
22511                });
22512
22513        let is_singleton = self.buffer_snapshot.is_singleton();
22514
22515        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22516        left_padding += if !is_singleton {
22517            ch_width * 4.0
22518        } else if show_runnables || show_breakpoints {
22519            ch_width * 3.0
22520        } else if show_git_gutter && show_line_numbers {
22521            ch_width * 2.0
22522        } else if show_git_gutter || show_line_numbers {
22523            ch_width
22524        } else {
22525            px(0.)
22526        };
22527
22528        let shows_folds = is_singleton && gutter_settings.folds;
22529
22530        let right_padding = if shows_folds && show_line_numbers {
22531            ch_width * 4.0
22532        } else if shows_folds || (!is_singleton && show_line_numbers) {
22533            ch_width * 3.0
22534        } else if show_line_numbers {
22535            ch_width
22536        } else {
22537            px(0.)
22538        };
22539
22540        Some(GutterDimensions {
22541            left_padding,
22542            right_padding,
22543            width: line_gutter_width + left_padding + right_padding,
22544            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22545            git_blame_entries_width,
22546        })
22547    }
22548
22549    pub fn render_crease_toggle(
22550        &self,
22551        buffer_row: MultiBufferRow,
22552        row_contains_cursor: bool,
22553        editor: Entity<Editor>,
22554        window: &mut Window,
22555        cx: &mut App,
22556    ) -> Option<AnyElement> {
22557        let folded = self.is_line_folded(buffer_row);
22558        let mut is_foldable = false;
22559
22560        if let Some(crease) = self
22561            .crease_snapshot
22562            .query_row(buffer_row, &self.buffer_snapshot)
22563        {
22564            is_foldable = true;
22565            match crease {
22566                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22567                    if let Some(render_toggle) = render_toggle {
22568                        let toggle_callback =
22569                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22570                                if folded {
22571                                    editor.update(cx, |editor, cx| {
22572                                        editor.fold_at(buffer_row, window, cx)
22573                                    });
22574                                } else {
22575                                    editor.update(cx, |editor, cx| {
22576                                        editor.unfold_at(buffer_row, window, cx)
22577                                    });
22578                                }
22579                            });
22580                        return Some((render_toggle)(
22581                            buffer_row,
22582                            folded,
22583                            toggle_callback,
22584                            window,
22585                            cx,
22586                        ));
22587                    }
22588                }
22589            }
22590        }
22591
22592        is_foldable |= self.starts_indent(buffer_row);
22593
22594        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22595            Some(
22596                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22597                    .toggle_state(folded)
22598                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22599                        if folded {
22600                            this.unfold_at(buffer_row, window, cx);
22601                        } else {
22602                            this.fold_at(buffer_row, window, cx);
22603                        }
22604                    }))
22605                    .into_any_element(),
22606            )
22607        } else {
22608            None
22609        }
22610    }
22611
22612    pub fn render_crease_trailer(
22613        &self,
22614        buffer_row: MultiBufferRow,
22615        window: &mut Window,
22616        cx: &mut App,
22617    ) -> Option<AnyElement> {
22618        let folded = self.is_line_folded(buffer_row);
22619        if let Crease::Inline { render_trailer, .. } = self
22620            .crease_snapshot
22621            .query_row(buffer_row, &self.buffer_snapshot)?
22622        {
22623            let render_trailer = render_trailer.as_ref()?;
22624            Some(render_trailer(buffer_row, folded, window, cx))
22625        } else {
22626            None
22627        }
22628    }
22629}
22630
22631impl Deref for EditorSnapshot {
22632    type Target = DisplaySnapshot;
22633
22634    fn deref(&self) -> &Self::Target {
22635        &self.display_snapshot
22636    }
22637}
22638
22639#[derive(Clone, Debug, PartialEq, Eq)]
22640pub enum EditorEvent {
22641    InputIgnored {
22642        text: Arc<str>,
22643    },
22644    InputHandled {
22645        utf16_range_to_replace: Option<Range<isize>>,
22646        text: Arc<str>,
22647    },
22648    ExcerptsAdded {
22649        buffer: Entity<Buffer>,
22650        predecessor: ExcerptId,
22651        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22652    },
22653    ExcerptsRemoved {
22654        ids: Vec<ExcerptId>,
22655        removed_buffer_ids: Vec<BufferId>,
22656    },
22657    BufferFoldToggled {
22658        ids: Vec<ExcerptId>,
22659        folded: bool,
22660    },
22661    ExcerptsEdited {
22662        ids: Vec<ExcerptId>,
22663    },
22664    ExcerptsExpanded {
22665        ids: Vec<ExcerptId>,
22666    },
22667    BufferEdited,
22668    Edited {
22669        transaction_id: clock::Lamport,
22670    },
22671    Reparsed(BufferId),
22672    Focused,
22673    FocusedIn,
22674    Blurred,
22675    DirtyChanged,
22676    Saved,
22677    TitleChanged,
22678    DiffBaseChanged,
22679    SelectionsChanged {
22680        local: bool,
22681    },
22682    ScrollPositionChanged {
22683        local: bool,
22684        autoscroll: bool,
22685    },
22686    Closed,
22687    TransactionUndone {
22688        transaction_id: clock::Lamport,
22689    },
22690    TransactionBegun {
22691        transaction_id: clock::Lamport,
22692    },
22693    Reloaded,
22694    CursorShapeChanged,
22695    PushedToNavHistory {
22696        anchor: Anchor,
22697        is_deactivate: bool,
22698    },
22699}
22700
22701impl EventEmitter<EditorEvent> for Editor {}
22702
22703impl Focusable for Editor {
22704    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22705        self.focus_handle.clone()
22706    }
22707}
22708
22709impl Render for Editor {
22710    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22711        let settings = ThemeSettings::get_global(cx);
22712
22713        let mut text_style = match self.mode {
22714            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22715                color: cx.theme().colors().editor_foreground,
22716                font_family: settings.ui_font.family.clone(),
22717                font_features: settings.ui_font.features.clone(),
22718                font_fallbacks: settings.ui_font.fallbacks.clone(),
22719                font_size: rems(0.875).into(),
22720                font_weight: settings.ui_font.weight,
22721                line_height: relative(settings.buffer_line_height.value()),
22722                ..Default::default()
22723            },
22724            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22725                color: cx.theme().colors().editor_foreground,
22726                font_family: settings.buffer_font.family.clone(),
22727                font_features: settings.buffer_font.features.clone(),
22728                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22729                font_size: settings.buffer_font_size(cx).into(),
22730                font_weight: settings.buffer_font.weight,
22731                line_height: relative(settings.buffer_line_height.value()),
22732                ..Default::default()
22733            },
22734        };
22735        if let Some(text_style_refinement) = &self.text_style_refinement {
22736            text_style.refine(text_style_refinement)
22737        }
22738
22739        let background = match self.mode {
22740            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22741            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22742            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22743            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22744        };
22745
22746        EditorElement::new(
22747            &cx.entity(),
22748            EditorStyle {
22749                background,
22750                border: cx.theme().colors().border,
22751                local_player: cx.theme().players().local(),
22752                text: text_style,
22753                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22754                syntax: cx.theme().syntax().clone(),
22755                status: cx.theme().status().clone(),
22756                inlay_hints_style: make_inlay_hints_style(cx),
22757                inline_completion_styles: make_suggestion_styles(cx),
22758                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22759                show_underlines: self.diagnostics_enabled(),
22760            },
22761        )
22762    }
22763}
22764
22765impl EntityInputHandler for Editor {
22766    fn text_for_range(
22767        &mut self,
22768        range_utf16: Range<usize>,
22769        adjusted_range: &mut Option<Range<usize>>,
22770        _: &mut Window,
22771        cx: &mut Context<Self>,
22772    ) -> Option<String> {
22773        let snapshot = self.buffer.read(cx).read(cx);
22774        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22775        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22776        if (start.0..end.0) != range_utf16 {
22777            adjusted_range.replace(start.0..end.0);
22778        }
22779        Some(snapshot.text_for_range(start..end).collect())
22780    }
22781
22782    fn selected_text_range(
22783        &mut self,
22784        ignore_disabled_input: bool,
22785        _: &mut Window,
22786        cx: &mut Context<Self>,
22787    ) -> Option<UTF16Selection> {
22788        // Prevent the IME menu from appearing when holding down an alphabetic key
22789        // while input is disabled.
22790        if !ignore_disabled_input && !self.input_enabled {
22791            return None;
22792        }
22793
22794        let selection = self.selections.newest::<OffsetUtf16>(cx);
22795        let range = selection.range();
22796
22797        Some(UTF16Selection {
22798            range: range.start.0..range.end.0,
22799            reversed: selection.reversed,
22800        })
22801    }
22802
22803    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22804        let snapshot = self.buffer.read(cx).read(cx);
22805        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22806        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22807    }
22808
22809    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22810        self.clear_highlights::<InputComposition>(cx);
22811        self.ime_transaction.take();
22812    }
22813
22814    fn replace_text_in_range(
22815        &mut self,
22816        range_utf16: Option<Range<usize>>,
22817        text: &str,
22818        window: &mut Window,
22819        cx: &mut Context<Self>,
22820    ) {
22821        if !self.input_enabled {
22822            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22823            return;
22824        }
22825
22826        self.transact(window, cx, |this, window, cx| {
22827            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22828                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22829                Some(this.selection_replacement_ranges(range_utf16, cx))
22830            } else {
22831                this.marked_text_ranges(cx)
22832            };
22833
22834            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22835                let newest_selection_id = this.selections.newest_anchor().id;
22836                this.selections
22837                    .all::<OffsetUtf16>(cx)
22838                    .iter()
22839                    .zip(ranges_to_replace.iter())
22840                    .find_map(|(selection, range)| {
22841                        if selection.id == newest_selection_id {
22842                            Some(
22843                                (range.start.0 as isize - selection.head().0 as isize)
22844                                    ..(range.end.0 as isize - selection.head().0 as isize),
22845                            )
22846                        } else {
22847                            None
22848                        }
22849                    })
22850            });
22851
22852            cx.emit(EditorEvent::InputHandled {
22853                utf16_range_to_replace: range_to_replace,
22854                text: text.into(),
22855            });
22856
22857            if let Some(new_selected_ranges) = new_selected_ranges {
22858                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22859                    selections.select_ranges(new_selected_ranges)
22860                });
22861                this.backspace(&Default::default(), window, cx);
22862            }
22863
22864            this.handle_input(text, window, cx);
22865        });
22866
22867        if let Some(transaction) = self.ime_transaction {
22868            self.buffer.update(cx, |buffer, cx| {
22869                buffer.group_until_transaction(transaction, cx);
22870            });
22871        }
22872
22873        self.unmark_text(window, cx);
22874    }
22875
22876    fn replace_and_mark_text_in_range(
22877        &mut self,
22878        range_utf16: Option<Range<usize>>,
22879        text: &str,
22880        new_selected_range_utf16: Option<Range<usize>>,
22881        window: &mut Window,
22882        cx: &mut Context<Self>,
22883    ) {
22884        if !self.input_enabled {
22885            return;
22886        }
22887
22888        let transaction = self.transact(window, cx, |this, window, cx| {
22889            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22890                let snapshot = this.buffer.read(cx).read(cx);
22891                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22892                    for marked_range in &mut marked_ranges {
22893                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22894                        marked_range.start.0 += relative_range_utf16.start;
22895                        marked_range.start =
22896                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22897                        marked_range.end =
22898                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22899                    }
22900                }
22901                Some(marked_ranges)
22902            } else if let Some(range_utf16) = range_utf16 {
22903                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22904                Some(this.selection_replacement_ranges(range_utf16, cx))
22905            } else {
22906                None
22907            };
22908
22909            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22910                let newest_selection_id = this.selections.newest_anchor().id;
22911                this.selections
22912                    .all::<OffsetUtf16>(cx)
22913                    .iter()
22914                    .zip(ranges_to_replace.iter())
22915                    .find_map(|(selection, range)| {
22916                        if selection.id == newest_selection_id {
22917                            Some(
22918                                (range.start.0 as isize - selection.head().0 as isize)
22919                                    ..(range.end.0 as isize - selection.head().0 as isize),
22920                            )
22921                        } else {
22922                            None
22923                        }
22924                    })
22925            });
22926
22927            cx.emit(EditorEvent::InputHandled {
22928                utf16_range_to_replace: range_to_replace,
22929                text: text.into(),
22930            });
22931
22932            if let Some(ranges) = ranges_to_replace {
22933                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22934                    s.select_ranges(ranges)
22935                });
22936            }
22937
22938            let marked_ranges = {
22939                let snapshot = this.buffer.read(cx).read(cx);
22940                this.selections
22941                    .disjoint_anchors()
22942                    .iter()
22943                    .map(|selection| {
22944                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22945                    })
22946                    .collect::<Vec<_>>()
22947            };
22948
22949            if text.is_empty() {
22950                this.unmark_text(window, cx);
22951            } else {
22952                this.highlight_text::<InputComposition>(
22953                    marked_ranges.clone(),
22954                    HighlightStyle {
22955                        underline: Some(UnderlineStyle {
22956                            thickness: px(1.),
22957                            color: None,
22958                            wavy: false,
22959                        }),
22960                        ..Default::default()
22961                    },
22962                    cx,
22963                );
22964            }
22965
22966            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22967            let use_autoclose = this.use_autoclose;
22968            let use_auto_surround = this.use_auto_surround;
22969            this.set_use_autoclose(false);
22970            this.set_use_auto_surround(false);
22971            this.handle_input(text, window, cx);
22972            this.set_use_autoclose(use_autoclose);
22973            this.set_use_auto_surround(use_auto_surround);
22974
22975            if let Some(new_selected_range) = new_selected_range_utf16 {
22976                let snapshot = this.buffer.read(cx).read(cx);
22977                let new_selected_ranges = marked_ranges
22978                    .into_iter()
22979                    .map(|marked_range| {
22980                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22981                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22982                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22983                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22984                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22985                    })
22986                    .collect::<Vec<_>>();
22987
22988                drop(snapshot);
22989                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22990                    selections.select_ranges(new_selected_ranges)
22991                });
22992            }
22993        });
22994
22995        self.ime_transaction = self.ime_transaction.or(transaction);
22996        if let Some(transaction) = self.ime_transaction {
22997            self.buffer.update(cx, |buffer, cx| {
22998                buffer.group_until_transaction(transaction, cx);
22999            });
23000        }
23001
23002        if self.text_highlights::<InputComposition>(cx).is_none() {
23003            self.ime_transaction.take();
23004        }
23005    }
23006
23007    fn bounds_for_range(
23008        &mut self,
23009        range_utf16: Range<usize>,
23010        element_bounds: gpui::Bounds<Pixels>,
23011        window: &mut Window,
23012        cx: &mut Context<Self>,
23013    ) -> Option<gpui::Bounds<Pixels>> {
23014        let text_layout_details = self.text_layout_details(window);
23015        let CharacterDimensions {
23016            em_width,
23017            em_advance,
23018            line_height,
23019        } = self.character_dimensions(window);
23020
23021        let snapshot = self.snapshot(window, cx);
23022        let scroll_position = snapshot.scroll_position();
23023        let scroll_left = scroll_position.x * em_advance;
23024
23025        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23026        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23027            + self.gutter_dimensions.full_width();
23028        let y = line_height * (start.row().as_f32() - scroll_position.y);
23029
23030        Some(Bounds {
23031            origin: element_bounds.origin + point(x, y),
23032            size: size(em_width, line_height),
23033        })
23034    }
23035
23036    fn character_index_for_point(
23037        &mut self,
23038        point: gpui::Point<Pixels>,
23039        _window: &mut Window,
23040        _cx: &mut Context<Self>,
23041    ) -> Option<usize> {
23042        let position_map = self.last_position_map.as_ref()?;
23043        if !position_map.text_hitbox.contains(&point) {
23044            return None;
23045        }
23046        let display_point = position_map.point_for_position(point).previous_valid;
23047        let anchor = position_map
23048            .snapshot
23049            .display_point_to_anchor(display_point, Bias::Left);
23050        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23051        Some(utf16_offset.0)
23052    }
23053}
23054
23055trait SelectionExt {
23056    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23057    fn spanned_rows(
23058        &self,
23059        include_end_if_at_line_start: bool,
23060        map: &DisplaySnapshot,
23061    ) -> Range<MultiBufferRow>;
23062}
23063
23064impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23065    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23066        let start = self
23067            .start
23068            .to_point(&map.buffer_snapshot)
23069            .to_display_point(map);
23070        let end = self
23071            .end
23072            .to_point(&map.buffer_snapshot)
23073            .to_display_point(map);
23074        if self.reversed {
23075            end..start
23076        } else {
23077            start..end
23078        }
23079    }
23080
23081    fn spanned_rows(
23082        &self,
23083        include_end_if_at_line_start: bool,
23084        map: &DisplaySnapshot,
23085    ) -> Range<MultiBufferRow> {
23086        let start = self.start.to_point(&map.buffer_snapshot);
23087        let mut end = self.end.to_point(&map.buffer_snapshot);
23088        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23089            end.row -= 1;
23090        }
23091
23092        let buffer_start = map.prev_line_boundary(start).0;
23093        let buffer_end = map.next_line_boundary(end).0;
23094        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23095    }
23096}
23097
23098impl<T: InvalidationRegion> InvalidationStack<T> {
23099    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23100    where
23101        S: Clone + ToOffset,
23102    {
23103        while let Some(region) = self.last() {
23104            let all_selections_inside_invalidation_ranges =
23105                if selections.len() == region.ranges().len() {
23106                    selections
23107                        .iter()
23108                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23109                        .all(|(selection, invalidation_range)| {
23110                            let head = selection.head().to_offset(buffer);
23111                            invalidation_range.start <= head && invalidation_range.end >= head
23112                        })
23113                } else {
23114                    false
23115                };
23116
23117            if all_selections_inside_invalidation_ranges {
23118                break;
23119            } else {
23120                self.pop();
23121            }
23122        }
23123    }
23124}
23125
23126impl<T> Default for InvalidationStack<T> {
23127    fn default() -> Self {
23128        Self(Default::default())
23129    }
23130}
23131
23132impl<T> Deref for InvalidationStack<T> {
23133    type Target = Vec<T>;
23134
23135    fn deref(&self) -> &Self::Target {
23136        &self.0
23137    }
23138}
23139
23140impl<T> DerefMut for InvalidationStack<T> {
23141    fn deref_mut(&mut self) -> &mut Self::Target {
23142        &mut self.0
23143    }
23144}
23145
23146impl InvalidationRegion for SnippetState {
23147    fn ranges(&self) -> &[Range<Anchor>] {
23148        &self.ranges[self.active_index]
23149    }
23150}
23151
23152fn inline_completion_edit_text(
23153    current_snapshot: &BufferSnapshot,
23154    edits: &[(Range<Anchor>, String)],
23155    edit_preview: &EditPreview,
23156    include_deletions: bool,
23157    cx: &App,
23158) -> HighlightedText {
23159    let edits = edits
23160        .iter()
23161        .map(|(anchor, text)| {
23162            (
23163                anchor.start.text_anchor..anchor.end.text_anchor,
23164                text.clone(),
23165            )
23166        })
23167        .collect::<Vec<_>>();
23168
23169    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23170}
23171
23172pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23173    match severity {
23174        lsp::DiagnosticSeverity::ERROR => colors.error,
23175        lsp::DiagnosticSeverity::WARNING => colors.warning,
23176        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23177        lsp::DiagnosticSeverity::HINT => colors.info,
23178        _ => colors.ignored,
23179    }
23180}
23181
23182pub fn styled_runs_for_code_label<'a>(
23183    label: &'a CodeLabel,
23184    syntax_theme: &'a theme::SyntaxTheme,
23185) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23186    let fade_out = HighlightStyle {
23187        fade_out: Some(0.35),
23188        ..Default::default()
23189    };
23190
23191    let mut prev_end = label.filter_range.end;
23192    label
23193        .runs
23194        .iter()
23195        .enumerate()
23196        .flat_map(move |(ix, (range, highlight_id))| {
23197            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23198                style
23199            } else {
23200                return Default::default();
23201            };
23202            let mut muted_style = style;
23203            muted_style.highlight(fade_out);
23204
23205            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23206            if range.start >= label.filter_range.end {
23207                if range.start > prev_end {
23208                    runs.push((prev_end..range.start, fade_out));
23209                }
23210                runs.push((range.clone(), muted_style));
23211            } else if range.end <= label.filter_range.end {
23212                runs.push((range.clone(), style));
23213            } else {
23214                runs.push((range.start..label.filter_range.end, style));
23215                runs.push((label.filter_range.end..range.end, muted_style));
23216            }
23217            prev_end = cmp::max(prev_end, range.end);
23218
23219            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23220                runs.push((prev_end..label.text.len(), fade_out));
23221            }
23222
23223            runs
23224        })
23225}
23226
23227pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23228    let mut prev_index = 0;
23229    let mut prev_codepoint: Option<char> = None;
23230    text.char_indices()
23231        .chain([(text.len(), '\0')])
23232        .filter_map(move |(index, codepoint)| {
23233            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23234            let is_boundary = index == text.len()
23235                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23236                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23237            if is_boundary {
23238                let chunk = &text[prev_index..index];
23239                prev_index = index;
23240                Some(chunk)
23241            } else {
23242                None
23243            }
23244        })
23245}
23246
23247pub trait RangeToAnchorExt: Sized {
23248    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23249
23250    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23251        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23252        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23253    }
23254}
23255
23256impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23257    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23258        let start_offset = self.start.to_offset(snapshot);
23259        let end_offset = self.end.to_offset(snapshot);
23260        if start_offset == end_offset {
23261            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23262        } else {
23263            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23264        }
23265    }
23266}
23267
23268pub trait RowExt {
23269    fn as_f32(&self) -> f32;
23270
23271    fn next_row(&self) -> Self;
23272
23273    fn previous_row(&self) -> Self;
23274
23275    fn minus(&self, other: Self) -> u32;
23276}
23277
23278impl RowExt for DisplayRow {
23279    fn as_f32(&self) -> f32 {
23280        self.0 as f32
23281    }
23282
23283    fn next_row(&self) -> Self {
23284        Self(self.0 + 1)
23285    }
23286
23287    fn previous_row(&self) -> Self {
23288        Self(self.0.saturating_sub(1))
23289    }
23290
23291    fn minus(&self, other: Self) -> u32 {
23292        self.0 - other.0
23293    }
23294}
23295
23296impl RowExt for MultiBufferRow {
23297    fn as_f32(&self) -> f32 {
23298        self.0 as f32
23299    }
23300
23301    fn next_row(&self) -> Self {
23302        Self(self.0 + 1)
23303    }
23304
23305    fn previous_row(&self) -> Self {
23306        Self(self.0.saturating_sub(1))
23307    }
23308
23309    fn minus(&self, other: Self) -> u32 {
23310        self.0 - other.0
23311    }
23312}
23313
23314trait RowRangeExt {
23315    type Row;
23316
23317    fn len(&self) -> usize;
23318
23319    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23320}
23321
23322impl RowRangeExt for Range<MultiBufferRow> {
23323    type Row = MultiBufferRow;
23324
23325    fn len(&self) -> usize {
23326        (self.end.0 - self.start.0) as usize
23327    }
23328
23329    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23330        (self.start.0..self.end.0).map(MultiBufferRow)
23331    }
23332}
23333
23334impl RowRangeExt for Range<DisplayRow> {
23335    type Row = DisplayRow;
23336
23337    fn len(&self) -> usize {
23338        (self.end.0 - self.start.0) as usize
23339    }
23340
23341    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23342        (self.start.0..self.end.0).map(DisplayRow)
23343    }
23344}
23345
23346/// If select range has more than one line, we
23347/// just point the cursor to range.start.
23348fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23349    if range.start.row == range.end.row {
23350        range
23351    } else {
23352        range.start..range.start
23353    }
23354}
23355pub struct KillRing(ClipboardItem);
23356impl Global for KillRing {}
23357
23358const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23359
23360enum BreakpointPromptEditAction {
23361    Log,
23362    Condition,
23363    HitCondition,
23364}
23365
23366struct BreakpointPromptEditor {
23367    pub(crate) prompt: Entity<Editor>,
23368    editor: WeakEntity<Editor>,
23369    breakpoint_anchor: Anchor,
23370    breakpoint: Breakpoint,
23371    edit_action: BreakpointPromptEditAction,
23372    block_ids: HashSet<CustomBlockId>,
23373    editor_margins: Arc<Mutex<EditorMargins>>,
23374    _subscriptions: Vec<Subscription>,
23375}
23376
23377impl BreakpointPromptEditor {
23378    const MAX_LINES: u8 = 4;
23379
23380    fn new(
23381        editor: WeakEntity<Editor>,
23382        breakpoint_anchor: Anchor,
23383        breakpoint: Breakpoint,
23384        edit_action: BreakpointPromptEditAction,
23385        window: &mut Window,
23386        cx: &mut Context<Self>,
23387    ) -> Self {
23388        let base_text = match edit_action {
23389            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23390            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23391            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23392        }
23393        .map(|msg| msg.to_string())
23394        .unwrap_or_default();
23395
23396        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23397        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23398
23399        let prompt = cx.new(|cx| {
23400            let mut prompt = Editor::new(
23401                EditorMode::AutoHeight {
23402                    min_lines: 1,
23403                    max_lines: Some(Self::MAX_LINES as usize),
23404                },
23405                buffer,
23406                None,
23407                window,
23408                cx,
23409            );
23410            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23411            prompt.set_show_cursor_when_unfocused(false, cx);
23412            prompt.set_placeholder_text(
23413                match edit_action {
23414                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23415                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23416                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23417                },
23418                cx,
23419            );
23420
23421            prompt
23422        });
23423
23424        Self {
23425            prompt,
23426            editor,
23427            breakpoint_anchor,
23428            breakpoint,
23429            edit_action,
23430            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23431            block_ids: Default::default(),
23432            _subscriptions: vec![],
23433        }
23434    }
23435
23436    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23437        self.block_ids.extend(block_ids)
23438    }
23439
23440    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23441        if let Some(editor) = self.editor.upgrade() {
23442            let message = self
23443                .prompt
23444                .read(cx)
23445                .buffer
23446                .read(cx)
23447                .as_singleton()
23448                .expect("A multi buffer in breakpoint prompt isn't possible")
23449                .read(cx)
23450                .as_rope()
23451                .to_string();
23452
23453            editor.update(cx, |editor, cx| {
23454                editor.edit_breakpoint_at_anchor(
23455                    self.breakpoint_anchor,
23456                    self.breakpoint.clone(),
23457                    match self.edit_action {
23458                        BreakpointPromptEditAction::Log => {
23459                            BreakpointEditAction::EditLogMessage(message.into())
23460                        }
23461                        BreakpointPromptEditAction::Condition => {
23462                            BreakpointEditAction::EditCondition(message.into())
23463                        }
23464                        BreakpointPromptEditAction::HitCondition => {
23465                            BreakpointEditAction::EditHitCondition(message.into())
23466                        }
23467                    },
23468                    cx,
23469                );
23470
23471                editor.remove_blocks(self.block_ids.clone(), None, cx);
23472                cx.focus_self(window);
23473            });
23474        }
23475    }
23476
23477    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23478        self.editor
23479            .update(cx, |editor, cx| {
23480                editor.remove_blocks(self.block_ids.clone(), None, cx);
23481                window.focus(&editor.focus_handle);
23482            })
23483            .log_err();
23484    }
23485
23486    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23487        let settings = ThemeSettings::get_global(cx);
23488        let text_style = TextStyle {
23489            color: if self.prompt.read(cx).read_only(cx) {
23490                cx.theme().colors().text_disabled
23491            } else {
23492                cx.theme().colors().text
23493            },
23494            font_family: settings.buffer_font.family.clone(),
23495            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23496            font_size: settings.buffer_font_size(cx).into(),
23497            font_weight: settings.buffer_font.weight,
23498            line_height: relative(settings.buffer_line_height.value()),
23499            ..Default::default()
23500        };
23501        EditorElement::new(
23502            &self.prompt,
23503            EditorStyle {
23504                background: cx.theme().colors().editor_background,
23505                local_player: cx.theme().players().local(),
23506                text: text_style,
23507                ..Default::default()
23508            },
23509        )
23510    }
23511}
23512
23513impl Render for BreakpointPromptEditor {
23514    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23515        let editor_margins = *self.editor_margins.lock();
23516        let gutter_dimensions = editor_margins.gutter;
23517        h_flex()
23518            .key_context("Editor")
23519            .bg(cx.theme().colors().editor_background)
23520            .border_y_1()
23521            .border_color(cx.theme().status().info_border)
23522            .size_full()
23523            .py(window.line_height() / 2.5)
23524            .on_action(cx.listener(Self::confirm))
23525            .on_action(cx.listener(Self::cancel))
23526            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23527            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23528    }
23529}
23530
23531impl Focusable for BreakpointPromptEditor {
23532    fn focus_handle(&self, cx: &App) -> FocusHandle {
23533        self.prompt.focus_handle(cx)
23534    }
23535}
23536
23537fn all_edits_insertions_or_deletions(
23538    edits: &Vec<(Range<Anchor>, String)>,
23539    snapshot: &MultiBufferSnapshot,
23540) -> bool {
23541    let mut all_insertions = true;
23542    let mut all_deletions = true;
23543
23544    for (range, new_text) in edits.iter() {
23545        let range_is_empty = range.to_offset(&snapshot).is_empty();
23546        let text_is_empty = new_text.is_empty();
23547
23548        if range_is_empty != text_is_empty {
23549            if range_is_empty {
23550                all_deletions = false;
23551            } else {
23552                all_insertions = false;
23553            }
23554        } else {
23555            return false;
23556        }
23557
23558        if !all_insertions && !all_deletions {
23559            return false;
23560        }
23561    }
23562    all_insertions || all_deletions
23563}
23564
23565struct MissingEditPredictionKeybindingTooltip;
23566
23567impl Render for MissingEditPredictionKeybindingTooltip {
23568    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23569        ui::tooltip_container(window, cx, |container, _, cx| {
23570            container
23571                .flex_shrink_0()
23572                .max_w_80()
23573                .min_h(rems_from_px(124.))
23574                .justify_between()
23575                .child(
23576                    v_flex()
23577                        .flex_1()
23578                        .text_ui_sm(cx)
23579                        .child(Label::new("Conflict with Accept Keybinding"))
23580                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23581                )
23582                .child(
23583                    h_flex()
23584                        .pb_1()
23585                        .gap_1()
23586                        .items_end()
23587                        .w_full()
23588                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23589                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23590                        }))
23591                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23592                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23593                        })),
23594                )
23595        })
23596    }
23597}
23598
23599#[derive(Debug, Clone, Copy, PartialEq)]
23600pub struct LineHighlight {
23601    pub background: Background,
23602    pub border: Option<gpui::Hsla>,
23603    pub include_gutter: bool,
23604    pub type_id: Option<TypeId>,
23605}
23606
23607struct LineManipulationResult {
23608    pub new_text: String,
23609    pub line_count_before: usize,
23610    pub line_count_after: usize,
23611}
23612
23613fn render_diff_hunk_controls(
23614    row: u32,
23615    status: &DiffHunkStatus,
23616    hunk_range: Range<Anchor>,
23617    is_created_file: bool,
23618    line_height: Pixels,
23619    editor: &Entity<Editor>,
23620    _window: &mut Window,
23621    cx: &mut App,
23622) -> AnyElement {
23623    h_flex()
23624        .h(line_height)
23625        .mr_1()
23626        .gap_1()
23627        .px_0p5()
23628        .pb_1()
23629        .border_x_1()
23630        .border_b_1()
23631        .border_color(cx.theme().colors().border_variant)
23632        .rounded_b_lg()
23633        .bg(cx.theme().colors().editor_background)
23634        .gap_1()
23635        .block_mouse_except_scroll()
23636        .shadow_md()
23637        .child(if status.has_secondary_hunk() {
23638            Button::new(("stage", row as u64), "Stage")
23639                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23640                .tooltip({
23641                    let focus_handle = editor.focus_handle(cx);
23642                    move |window, cx| {
23643                        Tooltip::for_action_in(
23644                            "Stage Hunk",
23645                            &::git::ToggleStaged,
23646                            &focus_handle,
23647                            window,
23648                            cx,
23649                        )
23650                    }
23651                })
23652                .on_click({
23653                    let editor = editor.clone();
23654                    move |_event, _window, cx| {
23655                        editor.update(cx, |editor, cx| {
23656                            editor.stage_or_unstage_diff_hunks(
23657                                true,
23658                                vec![hunk_range.start..hunk_range.start],
23659                                cx,
23660                            );
23661                        });
23662                    }
23663                })
23664        } else {
23665            Button::new(("unstage", row as u64), "Unstage")
23666                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23667                .tooltip({
23668                    let focus_handle = editor.focus_handle(cx);
23669                    move |window, cx| {
23670                        Tooltip::for_action_in(
23671                            "Unstage Hunk",
23672                            &::git::ToggleStaged,
23673                            &focus_handle,
23674                            window,
23675                            cx,
23676                        )
23677                    }
23678                })
23679                .on_click({
23680                    let editor = editor.clone();
23681                    move |_event, _window, cx| {
23682                        editor.update(cx, |editor, cx| {
23683                            editor.stage_or_unstage_diff_hunks(
23684                                false,
23685                                vec![hunk_range.start..hunk_range.start],
23686                                cx,
23687                            );
23688                        });
23689                    }
23690                })
23691        })
23692        .child(
23693            Button::new(("restore", row as u64), "Restore")
23694                .tooltip({
23695                    let focus_handle = editor.focus_handle(cx);
23696                    move |window, cx| {
23697                        Tooltip::for_action_in(
23698                            "Restore Hunk",
23699                            &::git::Restore,
23700                            &focus_handle,
23701                            window,
23702                            cx,
23703                        )
23704                    }
23705                })
23706                .on_click({
23707                    let editor = editor.clone();
23708                    move |_event, window, cx| {
23709                        editor.update(cx, |editor, cx| {
23710                            let snapshot = editor.snapshot(window, cx);
23711                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23712                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23713                        });
23714                    }
23715                })
23716                .disabled(is_created_file),
23717        )
23718        .when(
23719            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23720            |el| {
23721                el.child(
23722                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23723                        .shape(IconButtonShape::Square)
23724                        .icon_size(IconSize::Small)
23725                        // .disabled(!has_multiple_hunks)
23726                        .tooltip({
23727                            let focus_handle = editor.focus_handle(cx);
23728                            move |window, cx| {
23729                                Tooltip::for_action_in(
23730                                    "Next Hunk",
23731                                    &GoToHunk,
23732                                    &focus_handle,
23733                                    window,
23734                                    cx,
23735                                )
23736                            }
23737                        })
23738                        .on_click({
23739                            let editor = editor.clone();
23740                            move |_event, window, cx| {
23741                                editor.update(cx, |editor, cx| {
23742                                    let snapshot = editor.snapshot(window, cx);
23743                                    let position =
23744                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23745                                    editor.go_to_hunk_before_or_after_position(
23746                                        &snapshot,
23747                                        position,
23748                                        Direction::Next,
23749                                        window,
23750                                        cx,
23751                                    );
23752                                    editor.expand_selected_diff_hunks(cx);
23753                                });
23754                            }
23755                        }),
23756                )
23757                .child(
23758                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23759                        .shape(IconButtonShape::Square)
23760                        .icon_size(IconSize::Small)
23761                        // .disabled(!has_multiple_hunks)
23762                        .tooltip({
23763                            let focus_handle = editor.focus_handle(cx);
23764                            move |window, cx| {
23765                                Tooltip::for_action_in(
23766                                    "Previous Hunk",
23767                                    &GoToPreviousHunk,
23768                                    &focus_handle,
23769                                    window,
23770                                    cx,
23771                                )
23772                            }
23773                        })
23774                        .on_click({
23775                            let editor = editor.clone();
23776                            move |_event, window, cx| {
23777                                editor.update(cx, |editor, cx| {
23778                                    let snapshot = editor.snapshot(window, cx);
23779                                    let point =
23780                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23781                                    editor.go_to_hunk_before_or_after_position(
23782                                        &snapshot,
23783                                        point,
23784                                        Direction::Prev,
23785                                        window,
23786                                        cx,
23787                                    );
23788                                    editor.expand_selected_diff_hunks(cx);
23789                                });
23790                            }
23791                        }),
23792                )
23793            },
23794        )
23795        .into_any_element()
23796}