editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, 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.
 1308pub struct SelectionEffects {
 1309    nav_history: Option<bool>,
 1310    completions: bool,
 1311    scroll: Option<Autoscroll>,
 1312}
 1313
 1314impl Default for SelectionEffects {
 1315    fn default() -> Self {
 1316        Self {
 1317            nav_history: None,
 1318            completions: true,
 1319            scroll: Some(Autoscroll::fit()),
 1320        }
 1321    }
 1322}
 1323impl SelectionEffects {
 1324    pub fn scroll(scroll: Autoscroll) -> Self {
 1325        Self {
 1326            scroll: Some(scroll),
 1327            ..Default::default()
 1328        }
 1329    }
 1330
 1331    pub fn no_scroll() -> Self {
 1332        Self {
 1333            scroll: None,
 1334            ..Default::default()
 1335        }
 1336    }
 1337
 1338    pub fn completions(self, completions: bool) -> Self {
 1339        Self {
 1340            completions,
 1341            ..self
 1342        }
 1343    }
 1344
 1345    pub fn nav_history(self, nav_history: bool) -> Self {
 1346        Self {
 1347            nav_history: Some(nav_history),
 1348            ..self
 1349        }
 1350    }
 1351}
 1352
 1353struct DeferredSelectionEffectsState {
 1354    changed: bool,
 1355    effects: SelectionEffects,
 1356    old_cursor_position: Anchor,
 1357    history_entry: SelectionHistoryEntry,
 1358}
 1359
 1360#[derive(Default)]
 1361struct SelectionHistory {
 1362    #[allow(clippy::type_complexity)]
 1363    selections_by_transaction:
 1364        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1365    mode: SelectionHistoryMode,
 1366    undo_stack: VecDeque<SelectionHistoryEntry>,
 1367    redo_stack: VecDeque<SelectionHistoryEntry>,
 1368}
 1369
 1370impl SelectionHistory {
 1371    #[track_caller]
 1372    fn insert_transaction(
 1373        &mut self,
 1374        transaction_id: TransactionId,
 1375        selections: Arc<[Selection<Anchor>]>,
 1376    ) {
 1377        if selections.is_empty() {
 1378            log::error!(
 1379                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1380                std::panic::Location::caller()
 1381            );
 1382            return;
 1383        }
 1384        self.selections_by_transaction
 1385            .insert(transaction_id, (selections, None));
 1386    }
 1387
 1388    #[allow(clippy::type_complexity)]
 1389    fn transaction(
 1390        &self,
 1391        transaction_id: TransactionId,
 1392    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1393        self.selections_by_transaction.get(&transaction_id)
 1394    }
 1395
 1396    #[allow(clippy::type_complexity)]
 1397    fn transaction_mut(
 1398        &mut self,
 1399        transaction_id: TransactionId,
 1400    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1401        self.selections_by_transaction.get_mut(&transaction_id)
 1402    }
 1403
 1404    fn push(&mut self, entry: SelectionHistoryEntry) {
 1405        if !entry.selections.is_empty() {
 1406            match self.mode {
 1407                SelectionHistoryMode::Normal => {
 1408                    self.push_undo(entry);
 1409                    self.redo_stack.clear();
 1410                }
 1411                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1412                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1413                SelectionHistoryMode::Skipping => {}
 1414            }
 1415        }
 1416    }
 1417
 1418    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1419        if self
 1420            .undo_stack
 1421            .back()
 1422            .map_or(true, |e| e.selections != entry.selections)
 1423        {
 1424            self.undo_stack.push_back(entry);
 1425            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1426                self.undo_stack.pop_front();
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .redo_stack
 1434            .back()
 1435            .map_or(true, |e| e.selections != entry.selections)
 1436        {
 1437            self.redo_stack.push_back(entry);
 1438            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.redo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443}
 1444
 1445#[derive(Clone, Copy)]
 1446pub struct RowHighlightOptions {
 1447    pub autoscroll: bool,
 1448    pub include_gutter: bool,
 1449}
 1450
 1451impl Default for RowHighlightOptions {
 1452    fn default() -> Self {
 1453        Self {
 1454            autoscroll: Default::default(),
 1455            include_gutter: true,
 1456        }
 1457    }
 1458}
 1459
 1460struct RowHighlight {
 1461    index: usize,
 1462    range: Range<Anchor>,
 1463    color: Hsla,
 1464    options: RowHighlightOptions,
 1465    type_id: TypeId,
 1466}
 1467
 1468#[derive(Clone, Debug)]
 1469struct AddSelectionsState {
 1470    groups: Vec<AddSelectionsGroup>,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsGroup {
 1475    above: bool,
 1476    stack: Vec<usize>,
 1477}
 1478
 1479#[derive(Clone)]
 1480struct SelectNextState {
 1481    query: AhoCorasick,
 1482    wordwise: bool,
 1483    done: bool,
 1484}
 1485
 1486impl std::fmt::Debug for SelectNextState {
 1487    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1488        f.debug_struct(std::any::type_name::<Self>())
 1489            .field("wordwise", &self.wordwise)
 1490            .field("done", &self.done)
 1491            .finish()
 1492    }
 1493}
 1494
 1495#[derive(Debug)]
 1496struct AutocloseRegion {
 1497    selection_id: usize,
 1498    range: Range<Anchor>,
 1499    pair: BracketPair,
 1500}
 1501
 1502#[derive(Debug)]
 1503struct SnippetState {
 1504    ranges: Vec<Vec<Range<Anchor>>>,
 1505    active_index: usize,
 1506    choices: Vec<Option<Vec<String>>>,
 1507}
 1508
 1509#[doc(hidden)]
 1510pub struct RenameState {
 1511    pub range: Range<Anchor>,
 1512    pub old_name: Arc<str>,
 1513    pub editor: Entity<Editor>,
 1514    block_id: CustomBlockId,
 1515}
 1516
 1517struct InvalidationStack<T>(Vec<T>);
 1518
 1519struct RegisteredInlineCompletionProvider {
 1520    provider: Arc<dyn InlineCompletionProviderHandle>,
 1521    _subscription: Subscription,
 1522}
 1523
 1524#[derive(Debug, PartialEq, Eq)]
 1525pub struct ActiveDiagnosticGroup {
 1526    pub active_range: Range<Anchor>,
 1527    pub active_message: String,
 1528    pub group_id: usize,
 1529    pub blocks: HashSet<CustomBlockId>,
 1530}
 1531
 1532#[derive(Debug, PartialEq, Eq)]
 1533
 1534pub(crate) enum ActiveDiagnostic {
 1535    None,
 1536    All,
 1537    Group(ActiveDiagnosticGroup),
 1538}
 1539
 1540#[derive(Serialize, Deserialize, Clone, Debug)]
 1541pub struct ClipboardSelection {
 1542    /// The number of bytes in this selection.
 1543    pub len: usize,
 1544    /// Whether this was a full-line selection.
 1545    pub is_entire_line: bool,
 1546    /// The indentation of the first line when this content was originally copied.
 1547    pub first_line_indent: u32,
 1548}
 1549
 1550// selections, scroll behavior, was newest selection reversed
 1551type SelectSyntaxNodeHistoryState = (
 1552    Box<[Selection<usize>]>,
 1553    SelectSyntaxNodeScrollBehavior,
 1554    bool,
 1555);
 1556
 1557#[derive(Default)]
 1558struct SelectSyntaxNodeHistory {
 1559    stack: Vec<SelectSyntaxNodeHistoryState>,
 1560    // disable temporarily to allow changing selections without losing the stack
 1561    pub disable_clearing: bool,
 1562}
 1563
 1564impl SelectSyntaxNodeHistory {
 1565    pub fn try_clear(&mut self) {
 1566        if !self.disable_clearing {
 1567            self.stack.clear();
 1568        }
 1569    }
 1570
 1571    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1572        self.stack.push(selection);
 1573    }
 1574
 1575    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1576        self.stack.pop()
 1577    }
 1578}
 1579
 1580enum SelectSyntaxNodeScrollBehavior {
 1581    CursorTop,
 1582    FitSelection,
 1583    CursorBottom,
 1584}
 1585
 1586#[derive(Debug)]
 1587pub(crate) struct NavigationData {
 1588    cursor_anchor: Anchor,
 1589    cursor_position: Point,
 1590    scroll_anchor: ScrollAnchor,
 1591    scroll_top_row: u32,
 1592}
 1593
 1594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1595pub enum GotoDefinitionKind {
 1596    Symbol,
 1597    Declaration,
 1598    Type,
 1599    Implementation,
 1600}
 1601
 1602#[derive(Debug, Clone)]
 1603enum InlayHintRefreshReason {
 1604    ModifiersChanged(bool),
 1605    Toggle(bool),
 1606    SettingsChange(InlayHintSettings),
 1607    NewLinesShown,
 1608    BufferEdited(HashSet<Arc<Language>>),
 1609    RefreshRequested,
 1610    ExcerptsRemoved(Vec<ExcerptId>),
 1611}
 1612
 1613impl InlayHintRefreshReason {
 1614    fn description(&self) -> &'static str {
 1615        match self {
 1616            Self::ModifiersChanged(_) => "modifiers changed",
 1617            Self::Toggle(_) => "toggle",
 1618            Self::SettingsChange(_) => "settings change",
 1619            Self::NewLinesShown => "new lines shown",
 1620            Self::BufferEdited(_) => "buffer edited",
 1621            Self::RefreshRequested => "refresh requested",
 1622            Self::ExcerptsRemoved(_) => "excerpts removed",
 1623        }
 1624    }
 1625}
 1626
 1627pub enum FormatTarget {
 1628    Buffers(HashSet<Entity<Buffer>>),
 1629    Ranges(Vec<Range<MultiBufferPoint>>),
 1630}
 1631
 1632pub(crate) struct FocusedBlock {
 1633    id: BlockId,
 1634    focus_handle: WeakFocusHandle,
 1635}
 1636
 1637#[derive(Clone)]
 1638enum JumpData {
 1639    MultiBufferRow {
 1640        row: MultiBufferRow,
 1641        line_offset_from_top: u32,
 1642    },
 1643    MultiBufferPoint {
 1644        excerpt_id: ExcerptId,
 1645        position: Point,
 1646        anchor: text::Anchor,
 1647        line_offset_from_top: u32,
 1648    },
 1649}
 1650
 1651pub enum MultibufferSelectionMode {
 1652    First,
 1653    All,
 1654}
 1655
 1656#[derive(Clone, Copy, Debug, Default)]
 1657pub struct RewrapOptions {
 1658    pub override_language_settings: bool,
 1659    pub preserve_existing_whitespace: bool,
 1660}
 1661
 1662impl Editor {
 1663    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::full(), buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn auto_height(
 1676        min_lines: usize,
 1677        max_lines: usize,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::AutoHeight {
 1685                min_lines,
 1686                max_lines: Some(max_lines),
 1687            },
 1688            buffer,
 1689            None,
 1690            window,
 1691            cx,
 1692        )
 1693    }
 1694
 1695    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1696    /// The editor grows as tall as needed to fit its content.
 1697    pub fn auto_height_unbounded(
 1698        min_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: None,
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    pub fn for_buffer(
 1717        buffer: Entity<Buffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(EditorMode::full(), buffer, project, window, cx)
 1724    }
 1725
 1726    pub fn for_multibuffer(
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let mut clone = Self::new(
 1737            self.mode.clone(),
 1738            self.buffer.clone(),
 1739            self.project.clone(),
 1740            window,
 1741            cx,
 1742        );
 1743        self.display_map.update(cx, |display_map, cx| {
 1744            let snapshot = display_map.snapshot(cx);
 1745            clone.display_map.update(cx, |display_map, cx| {
 1746                display_map.set_state(&snapshot, cx);
 1747            });
 1748        });
 1749        clone.folds_did_change(cx);
 1750        clone.selections.clone_state(&self.selections);
 1751        clone.scroll_manager.clone_state(&self.scroll_manager);
 1752        clone.searchable = self.searchable;
 1753        clone.read_only = self.read_only;
 1754        clone
 1755    }
 1756
 1757    pub fn new(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        Editor::new_internal(mode, buffer, project, None, window, cx)
 1765    }
 1766
 1767    fn new_internal(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        display_map: Option<Entity<DisplayMap>>,
 1772        window: &mut Window,
 1773        cx: &mut Context<Self>,
 1774    ) -> Self {
 1775        debug_assert!(
 1776            display_map.is_none() || mode.is_minimap(),
 1777            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1778        );
 1779
 1780        let full_mode = mode.is_full();
 1781        let is_minimap = mode.is_minimap();
 1782        let diagnostics_max_severity = if full_mode {
 1783            EditorSettings::get_global(cx)
 1784                .diagnostics_max_severity
 1785                .unwrap_or(DiagnosticSeverity::Hint)
 1786        } else {
 1787            DiagnosticSeverity::Off
 1788        };
 1789        let style = window.text_style();
 1790        let font_size = style.font_size.to_pixels(window.rem_size());
 1791        let editor = cx.entity().downgrade();
 1792        let fold_placeholder = FoldPlaceholder {
 1793            constrain_width: true,
 1794            render: Arc::new(move |fold_id, fold_range, cx| {
 1795                let editor = editor.clone();
 1796                div()
 1797                    .id(fold_id)
 1798                    .bg(cx.theme().colors().ghost_element_background)
 1799                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1800                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1801                    .rounded_xs()
 1802                    .size_full()
 1803                    .cursor_pointer()
 1804                    .child("")
 1805                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1806                    .on_click(move |_, _window, cx| {
 1807                        editor
 1808                            .update(cx, |editor, cx| {
 1809                                editor.unfold_ranges(
 1810                                    &[fold_range.start..fold_range.end],
 1811                                    true,
 1812                                    false,
 1813                                    cx,
 1814                                );
 1815                                cx.stop_propagation();
 1816                            })
 1817                            .ok();
 1818                    })
 1819                    .into_any()
 1820            }),
 1821            merge_adjacent: true,
 1822            ..FoldPlaceholder::default()
 1823        };
 1824        let display_map = display_map.unwrap_or_else(|| {
 1825            cx.new(|cx| {
 1826                DisplayMap::new(
 1827                    buffer.clone(),
 1828                    style.font(),
 1829                    font_size,
 1830                    None,
 1831                    FILE_HEADER_HEIGHT,
 1832                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1833                    fold_placeholder,
 1834                    diagnostics_max_severity,
 1835                    cx,
 1836                )
 1837            })
 1838        });
 1839
 1840        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1841
 1842        let blink_manager = cx.new(|cx| {
 1843            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1844            if is_minimap {
 1845                blink_manager.disable(cx);
 1846            }
 1847            blink_manager
 1848        });
 1849
 1850        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1851            .then(|| language_settings::SoftWrap::None);
 1852
 1853        let mut project_subscriptions = Vec::new();
 1854        if full_mode {
 1855            if let Some(project) = project.as_ref() {
 1856                project_subscriptions.push(cx.subscribe_in(
 1857                    project,
 1858                    window,
 1859                    |editor, _, event, window, cx| match event {
 1860                        project::Event::RefreshCodeLens => {
 1861                            // we always query lens with actions, without storing them, always refreshing them
 1862                        }
 1863                        project::Event::RefreshInlayHints => {
 1864                            editor
 1865                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                        }
 1867                        project::Event::LanguageServerAdded(..)
 1868                        | project::Event::LanguageServerRemoved(..) => {
 1869                            if editor.tasks_update_task.is_none() {
 1870                                editor.tasks_update_task =
 1871                                    Some(editor.refresh_runnables(window, cx));
 1872                            }
 1873                            editor.update_lsp_data(true, None, window, cx);
 1874                        }
 1875                        project::Event::SnippetEdit(id, snippet_edits) => {
 1876                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                                let focus_handle = editor.focus_handle(cx);
 1878                                if focus_handle.is_focused(window) {
 1879                                    let snapshot = buffer.read(cx).snapshot();
 1880                                    for (range, snippet) in snippet_edits {
 1881                                        let editor_range =
 1882                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                        editor
 1884                                            .insert_snippet(
 1885                                                &[editor_range],
 1886                                                snippet.clone(),
 1887                                                window,
 1888                                                cx,
 1889                                            )
 1890                                            .ok();
 1891                                    }
 1892                                }
 1893                            }
 1894                        }
 1895                        _ => {}
 1896                    },
 1897                ));
 1898                if let Some(task_inventory) = project
 1899                    .read(cx)
 1900                    .task_store()
 1901                    .read(cx)
 1902                    .task_inventory()
 1903                    .cloned()
 1904                {
 1905                    project_subscriptions.push(cx.observe_in(
 1906                        &task_inventory,
 1907                        window,
 1908                        |editor, _, window, cx| {
 1909                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1910                        },
 1911                    ));
 1912                };
 1913
 1914                project_subscriptions.push(cx.subscribe_in(
 1915                    &project.read(cx).breakpoint_store(),
 1916                    window,
 1917                    |editor, _, event, window, cx| match event {
 1918                        BreakpointStoreEvent::ClearDebugLines => {
 1919                            editor.clear_row_highlights::<ActiveDebugLine>();
 1920                            editor.refresh_inline_values(cx);
 1921                        }
 1922                        BreakpointStoreEvent::SetDebugLine => {
 1923                            if editor.go_to_active_debug_line(window, cx) {
 1924                                cx.stop_propagation();
 1925                            }
 1926
 1927                            editor.refresh_inline_values(cx);
 1928                        }
 1929                        _ => {}
 1930                    },
 1931                ));
 1932                let git_store = project.read(cx).git_store().clone();
 1933                let project = project.clone();
 1934                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1935                    match event {
 1936                        GitStoreEvent::RepositoryUpdated(
 1937                            _,
 1938                            RepositoryEvent::Updated {
 1939                                new_instance: true, ..
 1940                            },
 1941                            _,
 1942                        ) => {
 1943                            this.load_diff_task = Some(
 1944                                update_uncommitted_diff_for_buffer(
 1945                                    cx.entity(),
 1946                                    &project,
 1947                                    this.buffer.read(cx).all_buffers(),
 1948                                    this.buffer.clone(),
 1949                                    cx,
 1950                                )
 1951                                .shared(),
 1952                            );
 1953                        }
 1954                        _ => {}
 1955                    }
 1956                }));
 1957            }
 1958        }
 1959
 1960        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1961
 1962        let inlay_hint_settings =
 1963            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1964        let focus_handle = cx.focus_handle();
 1965        if !is_minimap {
 1966            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1967                .detach();
 1968            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1969                .detach();
 1970            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1971                .detach();
 1972            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1973                .detach();
 1974            cx.observe_pending_input(window, Self::observe_pending_input)
 1975                .detach();
 1976        }
 1977
 1978        let show_indent_guides = if matches!(
 1979            mode,
 1980            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1981        ) {
 1982            Some(false)
 1983        } else {
 1984            None
 1985        };
 1986
 1987        let breakpoint_store = match (&mode, project.as_ref()) {
 1988            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1989            _ => None,
 1990        };
 1991
 1992        let mut code_action_providers = Vec::new();
 1993        let mut load_uncommitted_diff = None;
 1994        if let Some(project) = project.clone() {
 1995            load_uncommitted_diff = Some(
 1996                update_uncommitted_diff_for_buffer(
 1997                    cx.entity(),
 1998                    &project,
 1999                    buffer.read(cx).all_buffers(),
 2000                    buffer.clone(),
 2001                    cx,
 2002                )
 2003                .shared(),
 2004            );
 2005            code_action_providers.push(Rc::new(project) as Rc<_>);
 2006        }
 2007
 2008        let mut editor = Self {
 2009            focus_handle,
 2010            show_cursor_when_unfocused: false,
 2011            last_focused_descendant: None,
 2012            buffer: buffer.clone(),
 2013            display_map: display_map.clone(),
 2014            selections,
 2015            scroll_manager: ScrollManager::new(cx),
 2016            columnar_selection_state: None,
 2017            add_selections_state: None,
 2018            select_next_state: None,
 2019            select_prev_state: None,
 2020            selection_history: SelectionHistory::default(),
 2021            defer_selection_effects: false,
 2022            deferred_selection_effects_state: None,
 2023            autoclose_regions: Vec::new(),
 2024            snippet_stack: InvalidationStack::default(),
 2025            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2026            ime_transaction: None,
 2027            active_diagnostics: ActiveDiagnostic::None,
 2028            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2029            inline_diagnostics_update: Task::ready(()),
 2030            inline_diagnostics: Vec::new(),
 2031            soft_wrap_mode_override,
 2032            diagnostics_max_severity,
 2033            hard_wrap: None,
 2034            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2035            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2037            project,
 2038            blink_manager: blink_manager.clone(),
 2039            show_local_selections: true,
 2040            show_scrollbars: ScrollbarAxes {
 2041                horizontal: full_mode,
 2042                vertical: full_mode,
 2043            },
 2044            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2045            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2046            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2047            show_gutter: full_mode,
 2048            show_line_numbers: (!full_mode).then_some(false),
 2049            use_relative_line_numbers: None,
 2050            disable_expand_excerpt_buttons: !full_mode,
 2051            show_git_diff_gutter: None,
 2052            show_code_actions: None,
 2053            show_runnables: None,
 2054            show_breakpoints: None,
 2055            show_wrap_guides: None,
 2056            show_indent_guides,
 2057            placeholder_text: None,
 2058            highlight_order: 0,
 2059            highlighted_rows: HashMap::default(),
 2060            background_highlights: TreeMap::default(),
 2061            gutter_highlights: TreeMap::default(),
 2062            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2063            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2064            nav_history: None,
 2065            context_menu: RefCell::new(None),
 2066            context_menu_options: None,
 2067            mouse_context_menu: None,
 2068            completion_tasks: Vec::new(),
 2069            inline_blame_popover: None,
 2070            inline_blame_popover_show_task: None,
 2071            signature_help_state: SignatureHelpState::default(),
 2072            auto_signature_help: None,
 2073            find_all_references_task_sources: Vec::new(),
 2074            next_completion_id: 0,
 2075            next_inlay_id: 0,
 2076            code_action_providers,
 2077            available_code_actions: None,
 2078            code_actions_task: None,
 2079            quick_selection_highlight_task: None,
 2080            debounced_selection_highlight_task: None,
 2081            document_highlights_task: None,
 2082            linked_editing_range_task: None,
 2083            pending_rename: None,
 2084            searchable: !is_minimap,
 2085            cursor_shape: EditorSettings::get_global(cx)
 2086                .cursor_shape
 2087                .unwrap_or_default(),
 2088            current_line_highlight: None,
 2089            autoindent_mode: Some(AutoindentMode::EachLine),
 2090            collapse_matches: false,
 2091            workspace: None,
 2092            input_enabled: !is_minimap,
 2093            use_modal_editing: full_mode,
 2094            read_only: is_minimap,
 2095            use_autoclose: true,
 2096            use_auto_surround: true,
 2097            auto_replace_emoji_shortcode: false,
 2098            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2099            leader_id: None,
 2100            remote_id: None,
 2101            hover_state: HoverState::default(),
 2102            pending_mouse_down: None,
 2103            hovered_link_state: None,
 2104            edit_prediction_provider: None,
 2105            active_inline_completion: None,
 2106            stale_inline_completion_in_menu: None,
 2107            edit_prediction_preview: EditPredictionPreview::Inactive {
 2108                released_too_fast: false,
 2109            },
 2110            inline_diagnostics_enabled: full_mode,
 2111            diagnostics_enabled: full_mode,
 2112            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2113            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2114            gutter_hovered: false,
 2115            pixel_position_of_newest_cursor: None,
 2116            last_bounds: None,
 2117            last_position_map: None,
 2118            expect_bounds_change: None,
 2119            gutter_dimensions: GutterDimensions::default(),
 2120            style: None,
 2121            show_cursor_names: false,
 2122            hovered_cursors: HashMap::default(),
 2123            next_editor_action_id: EditorActionId::default(),
 2124            editor_actions: Rc::default(),
 2125            inline_completions_hidden_for_vim_mode: false,
 2126            show_inline_completions_override: None,
 2127            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2128            edit_prediction_settings: EditPredictionSettings::Disabled,
 2129            edit_prediction_indent_conflict: false,
 2130            edit_prediction_requires_modifier_in_indent_conflict: true,
 2131            custom_context_menu: None,
 2132            show_git_blame_gutter: false,
 2133            show_git_blame_inline: false,
 2134            show_selection_menu: None,
 2135            show_git_blame_inline_delay_task: None,
 2136            git_blame_inline_enabled: full_mode
 2137                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2138            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2139            serialize_dirty_buffers: !is_minimap
 2140                && ProjectSettings::get_global(cx)
 2141                    .session
 2142                    .restore_unsaved_buffers,
 2143            blame: None,
 2144            blame_subscription: None,
 2145            tasks: BTreeMap::default(),
 2146
 2147            breakpoint_store,
 2148            gutter_breakpoint_indicator: (None, None),
 2149            hovered_diff_hunk_row: None,
 2150            _subscriptions: (!is_minimap)
 2151                .then(|| {
 2152                    vec![
 2153                        cx.observe(&buffer, Self::on_buffer_changed),
 2154                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2155                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2156                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2157                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2158                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2159                        cx.observe_window_activation(window, |editor, window, cx| {
 2160                            let active = window.is_window_active();
 2161                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2162                                if active {
 2163                                    blink_manager.enable(cx);
 2164                                } else {
 2165                                    blink_manager.disable(cx);
 2166                                }
 2167                            });
 2168                            if active {
 2169                                editor.show_mouse_cursor(cx);
 2170                            }
 2171                        }),
 2172                    ]
 2173                })
 2174                .unwrap_or_default(),
 2175            tasks_update_task: None,
 2176            pull_diagnostics_task: Task::ready(()),
 2177            colors: None,
 2178            next_color_inlay_id: 0,
 2179            linked_edit_ranges: Default::default(),
 2180            in_project_search: false,
 2181            previous_search_ranges: None,
 2182            breadcrumb_header: None,
 2183            focused_block: None,
 2184            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2185            addons: HashMap::default(),
 2186            registered_buffers: HashMap::default(),
 2187            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2188            selection_mark_mode: false,
 2189            toggle_fold_multiple_buffers: Task::ready(()),
 2190            serialize_selections: Task::ready(()),
 2191            serialize_folds: Task::ready(()),
 2192            text_style_refinement: None,
 2193            load_diff_task: load_uncommitted_diff,
 2194            temporary_diff_override: false,
 2195            mouse_cursor_hidden: false,
 2196            minimap: None,
 2197            hide_mouse_mode: EditorSettings::get_global(cx)
 2198                .hide_mouse
 2199                .unwrap_or_default(),
 2200            change_list: ChangeList::new(),
 2201            mode,
 2202            selection_drag_state: SelectionDragState::None,
 2203            folding_newlines: Task::ready(()),
 2204        };
 2205
 2206        if is_minimap {
 2207            return editor;
 2208        }
 2209
 2210        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2211            editor
 2212                ._subscriptions
 2213                .push(cx.observe(breakpoints, |_, _, cx| {
 2214                    cx.notify();
 2215                }));
 2216        }
 2217        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2218        editor._subscriptions.extend(project_subscriptions);
 2219
 2220        editor._subscriptions.push(cx.subscribe_in(
 2221            &cx.entity(),
 2222            window,
 2223            |editor, _, e: &EditorEvent, window, cx| match e {
 2224                EditorEvent::ScrollPositionChanged { local, .. } => {
 2225                    if *local {
 2226                        let new_anchor = editor.scroll_manager.anchor();
 2227                        let snapshot = editor.snapshot(window, cx);
 2228                        editor.update_restoration_data(cx, move |data| {
 2229                            data.scroll_position = (
 2230                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2231                                new_anchor.offset,
 2232                            );
 2233                        });
 2234                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2235                        editor.inline_blame_popover.take();
 2236                    }
 2237                }
 2238                EditorEvent::Edited { .. } => {
 2239                    if !vim_enabled(cx) {
 2240                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2241                        let pop_state = editor
 2242                            .change_list
 2243                            .last()
 2244                            .map(|previous| {
 2245                                previous.len() == selections.len()
 2246                                    && previous.iter().enumerate().all(|(ix, p)| {
 2247                                        p.to_display_point(&map).row()
 2248                                            == selections[ix].head().row()
 2249                                    })
 2250                            })
 2251                            .unwrap_or(false);
 2252                        let new_positions = selections
 2253                            .into_iter()
 2254                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2255                            .collect();
 2256                        editor
 2257                            .change_list
 2258                            .push_to_change_list(pop_state, new_positions);
 2259                    }
 2260                }
 2261                _ => (),
 2262            },
 2263        ));
 2264
 2265        if let Some(dap_store) = editor
 2266            .project
 2267            .as_ref()
 2268            .map(|project| project.read(cx).dap_store())
 2269        {
 2270            let weak_editor = cx.weak_entity();
 2271
 2272            editor
 2273                ._subscriptions
 2274                .push(
 2275                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2276                        let session_entity = cx.entity();
 2277                        weak_editor
 2278                            .update(cx, |editor, cx| {
 2279                                editor._subscriptions.push(
 2280                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2281                                );
 2282                            })
 2283                            .ok();
 2284                    }),
 2285                );
 2286
 2287            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2288                editor
 2289                    ._subscriptions
 2290                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2291            }
 2292        }
 2293
 2294        // skip adding the initial selection to selection history
 2295        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2296        editor.end_selection(window, cx);
 2297        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2298
 2299        editor.scroll_manager.show_scrollbars(window, cx);
 2300        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2301
 2302        if full_mode {
 2303            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2304            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2305
 2306            if editor.git_blame_inline_enabled {
 2307                editor.start_git_blame_inline(false, window, cx);
 2308            }
 2309
 2310            editor.go_to_active_debug_line(window, cx);
 2311
 2312            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2313                if let Some(project) = editor.project.as_ref() {
 2314                    let handle = project.update(cx, |project, cx| {
 2315                        project.register_buffer_with_language_servers(&buffer, cx)
 2316                    });
 2317                    editor
 2318                        .registered_buffers
 2319                        .insert(buffer.read(cx).remote_id(), handle);
 2320                }
 2321            }
 2322
 2323            editor.minimap =
 2324                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2325            editor.colors = Some(LspColorData::new(cx));
 2326            editor.update_lsp_data(false, None, window, cx);
 2327        }
 2328
 2329        if editor.mode.is_full() {
 2330            editor.report_editor_event("Editor Opened", None, cx);
 2331        }
 2332
 2333        editor
 2334    }
 2335
 2336    pub fn deploy_mouse_context_menu(
 2337        &mut self,
 2338        position: gpui::Point<Pixels>,
 2339        context_menu: Entity<ContextMenu>,
 2340        window: &mut Window,
 2341        cx: &mut Context<Self>,
 2342    ) {
 2343        self.mouse_context_menu = Some(MouseContextMenu::new(
 2344            self,
 2345            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2346            context_menu,
 2347            window,
 2348            cx,
 2349        ));
 2350    }
 2351
 2352    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2353        self.mouse_context_menu
 2354            .as_ref()
 2355            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2356    }
 2357
 2358    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2359        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2360    }
 2361
 2362    fn key_context_internal(
 2363        &self,
 2364        has_active_edit_prediction: bool,
 2365        window: &Window,
 2366        cx: &App,
 2367    ) -> KeyContext {
 2368        let mut key_context = KeyContext::new_with_defaults();
 2369        key_context.add("Editor");
 2370        let mode = match self.mode {
 2371            EditorMode::SingleLine { .. } => "single_line",
 2372            EditorMode::AutoHeight { .. } => "auto_height",
 2373            EditorMode::Minimap { .. } => "minimap",
 2374            EditorMode::Full { .. } => "full",
 2375        };
 2376
 2377        if EditorSettings::jupyter_enabled(cx) {
 2378            key_context.add("jupyter");
 2379        }
 2380
 2381        key_context.set("mode", mode);
 2382        if self.pending_rename.is_some() {
 2383            key_context.add("renaming");
 2384        }
 2385
 2386        match self.context_menu.borrow().as_ref() {
 2387            Some(CodeContextMenu::Completions(menu)) => {
 2388                if menu.visible() {
 2389                    key_context.add("menu");
 2390                    key_context.add("showing_completions");
 2391                }
 2392            }
 2393            Some(CodeContextMenu::CodeActions(menu)) => {
 2394                if menu.visible() {
 2395                    key_context.add("menu");
 2396                    key_context.add("showing_code_actions")
 2397                }
 2398            }
 2399            None => {}
 2400        }
 2401
 2402        if self.signature_help_state.has_multiple_signatures() {
 2403            key_context.add("showing_signature_help");
 2404        }
 2405
 2406        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2407        if !self.focus_handle(cx).contains_focused(window, cx)
 2408            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2409        {
 2410            for addon in self.addons.values() {
 2411                addon.extend_key_context(&mut key_context, cx)
 2412            }
 2413        }
 2414
 2415        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2416            if let Some(extension) = singleton_buffer
 2417                .read(cx)
 2418                .file()
 2419                .and_then(|file| file.path().extension()?.to_str())
 2420            {
 2421                key_context.set("extension", extension.to_string());
 2422            }
 2423        } else {
 2424            key_context.add("multibuffer");
 2425        }
 2426
 2427        if has_active_edit_prediction {
 2428            if self.edit_prediction_in_conflict() {
 2429                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2430            } else {
 2431                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2432                key_context.add("copilot_suggestion");
 2433            }
 2434        }
 2435
 2436        if self.selection_mark_mode {
 2437            key_context.add("selection_mode");
 2438        }
 2439
 2440        key_context
 2441    }
 2442
 2443    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2444        if self.mouse_cursor_hidden {
 2445            self.mouse_cursor_hidden = false;
 2446            cx.notify();
 2447        }
 2448    }
 2449
 2450    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2451        let hide_mouse_cursor = match origin {
 2452            HideMouseCursorOrigin::TypingAction => {
 2453                matches!(
 2454                    self.hide_mouse_mode,
 2455                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2456                )
 2457            }
 2458            HideMouseCursorOrigin::MovementAction => {
 2459                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2460            }
 2461        };
 2462        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2463            self.mouse_cursor_hidden = hide_mouse_cursor;
 2464            cx.notify();
 2465        }
 2466    }
 2467
 2468    pub fn edit_prediction_in_conflict(&self) -> bool {
 2469        if !self.show_edit_predictions_in_menu() {
 2470            return false;
 2471        }
 2472
 2473        let showing_completions = self
 2474            .context_menu
 2475            .borrow()
 2476            .as_ref()
 2477            .map_or(false, |context| {
 2478                matches!(context, CodeContextMenu::Completions(_))
 2479            });
 2480
 2481        showing_completions
 2482            || self.edit_prediction_requires_modifier()
 2483            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2484            // bindings to insert tab characters.
 2485            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2486    }
 2487
 2488    pub fn accept_edit_prediction_keybind(
 2489        &self,
 2490        accept_partial: bool,
 2491        window: &Window,
 2492        cx: &App,
 2493    ) -> AcceptEditPredictionBinding {
 2494        let key_context = self.key_context_internal(true, window, cx);
 2495        let in_conflict = self.edit_prediction_in_conflict();
 2496
 2497        let bindings = if accept_partial {
 2498            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2499        } else {
 2500            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2501        };
 2502
 2503        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2504        // just the first one.
 2505        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2506            !in_conflict
 2507                || binding
 2508                    .keystrokes()
 2509                    .first()
 2510                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2511        }))
 2512    }
 2513
 2514    pub fn new_file(
 2515        workspace: &mut Workspace,
 2516        _: &workspace::NewFile,
 2517        window: &mut Window,
 2518        cx: &mut Context<Workspace>,
 2519    ) {
 2520        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2521            "Failed to create buffer",
 2522            window,
 2523            cx,
 2524            |e, _, _| match e.error_code() {
 2525                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2526                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2527                e.error_tag("required").unwrap_or("the latest version")
 2528            )),
 2529                _ => None,
 2530            },
 2531        );
 2532    }
 2533
 2534    pub fn new_in_workspace(
 2535        workspace: &mut Workspace,
 2536        window: &mut Window,
 2537        cx: &mut Context<Workspace>,
 2538    ) -> Task<Result<Entity<Editor>>> {
 2539        let project = workspace.project().clone();
 2540        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2541
 2542        cx.spawn_in(window, async move |workspace, cx| {
 2543            let buffer = create.await?;
 2544            workspace.update_in(cx, |workspace, window, cx| {
 2545                let editor =
 2546                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2547                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2548                editor
 2549            })
 2550        })
 2551    }
 2552
 2553    fn new_file_vertical(
 2554        workspace: &mut Workspace,
 2555        _: &workspace::NewFileSplitVertical,
 2556        window: &mut Window,
 2557        cx: &mut Context<Workspace>,
 2558    ) {
 2559        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2560    }
 2561
 2562    fn new_file_horizontal(
 2563        workspace: &mut Workspace,
 2564        _: &workspace::NewFileSplitHorizontal,
 2565        window: &mut Window,
 2566        cx: &mut Context<Workspace>,
 2567    ) {
 2568        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2569    }
 2570
 2571    fn new_file_in_direction(
 2572        workspace: &mut Workspace,
 2573        direction: SplitDirection,
 2574        window: &mut Window,
 2575        cx: &mut Context<Workspace>,
 2576    ) {
 2577        let project = workspace.project().clone();
 2578        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2579
 2580        cx.spawn_in(window, async move |workspace, cx| {
 2581            let buffer = create.await?;
 2582            workspace.update_in(cx, move |workspace, window, cx| {
 2583                workspace.split_item(
 2584                    direction,
 2585                    Box::new(
 2586                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2587                    ),
 2588                    window,
 2589                    cx,
 2590                )
 2591            })?;
 2592            anyhow::Ok(())
 2593        })
 2594        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2595            match e.error_code() {
 2596                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2597                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2598                e.error_tag("required").unwrap_or("the latest version")
 2599            )),
 2600                _ => None,
 2601            }
 2602        });
 2603    }
 2604
 2605    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2606        self.leader_id
 2607    }
 2608
 2609    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2610        &self.buffer
 2611    }
 2612
 2613    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2614        self.workspace.as_ref()?.0.upgrade()
 2615    }
 2616
 2617    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2618        self.buffer().read(cx).title(cx)
 2619    }
 2620
 2621    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2622        let git_blame_gutter_max_author_length = self
 2623            .render_git_blame_gutter(cx)
 2624            .then(|| {
 2625                if let Some(blame) = self.blame.as_ref() {
 2626                    let max_author_length =
 2627                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2628                    Some(max_author_length)
 2629                } else {
 2630                    None
 2631                }
 2632            })
 2633            .flatten();
 2634
 2635        EditorSnapshot {
 2636            mode: self.mode.clone(),
 2637            show_gutter: self.show_gutter,
 2638            show_line_numbers: self.show_line_numbers,
 2639            show_git_diff_gutter: self.show_git_diff_gutter,
 2640            show_code_actions: self.show_code_actions,
 2641            show_runnables: self.show_runnables,
 2642            show_breakpoints: self.show_breakpoints,
 2643            git_blame_gutter_max_author_length,
 2644            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2645            scroll_anchor: self.scroll_manager.anchor(),
 2646            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2647            placeholder_text: self.placeholder_text.clone(),
 2648            is_focused: self.focus_handle.is_focused(window),
 2649            current_line_highlight: self
 2650                .current_line_highlight
 2651                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2652            gutter_hovered: self.gutter_hovered,
 2653        }
 2654    }
 2655
 2656    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2657        self.buffer.read(cx).language_at(point, cx)
 2658    }
 2659
 2660    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2661        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2662    }
 2663
 2664    pub fn active_excerpt(
 2665        &self,
 2666        cx: &App,
 2667    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2668        self.buffer
 2669            .read(cx)
 2670            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2671    }
 2672
 2673    pub fn mode(&self) -> &EditorMode {
 2674        &self.mode
 2675    }
 2676
 2677    pub fn set_mode(&mut self, mode: EditorMode) {
 2678        self.mode = mode;
 2679    }
 2680
 2681    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2682        self.collaboration_hub.as_deref()
 2683    }
 2684
 2685    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2686        self.collaboration_hub = Some(hub);
 2687    }
 2688
 2689    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2690        self.in_project_search = in_project_search;
 2691    }
 2692
 2693    pub fn set_custom_context_menu(
 2694        &mut self,
 2695        f: impl 'static
 2696        + Fn(
 2697            &mut Self,
 2698            DisplayPoint,
 2699            &mut Window,
 2700            &mut Context<Self>,
 2701        ) -> Option<Entity<ui::ContextMenu>>,
 2702    ) {
 2703        self.custom_context_menu = Some(Box::new(f))
 2704    }
 2705
 2706    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2707        self.completion_provider = provider;
 2708    }
 2709
 2710    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2711        self.semantics_provider.clone()
 2712    }
 2713
 2714    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2715        self.semantics_provider = provider;
 2716    }
 2717
 2718    pub fn set_edit_prediction_provider<T>(
 2719        &mut self,
 2720        provider: Option<Entity<T>>,
 2721        window: &mut Window,
 2722        cx: &mut Context<Self>,
 2723    ) where
 2724        T: EditPredictionProvider,
 2725    {
 2726        self.edit_prediction_provider =
 2727            provider.map(|provider| RegisteredInlineCompletionProvider {
 2728                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2729                    if this.focus_handle.is_focused(window) {
 2730                        this.update_visible_inline_completion(window, cx);
 2731                    }
 2732                }),
 2733                provider: Arc::new(provider),
 2734            });
 2735        self.update_edit_prediction_settings(cx);
 2736        self.refresh_inline_completion(false, false, window, cx);
 2737    }
 2738
 2739    pub fn placeholder_text(&self) -> Option<&str> {
 2740        self.placeholder_text.as_deref()
 2741    }
 2742
 2743    pub fn set_placeholder_text(
 2744        &mut self,
 2745        placeholder_text: impl Into<Arc<str>>,
 2746        cx: &mut Context<Self>,
 2747    ) {
 2748        let placeholder_text = Some(placeholder_text.into());
 2749        if self.placeholder_text != placeholder_text {
 2750            self.placeholder_text = placeholder_text;
 2751            cx.notify();
 2752        }
 2753    }
 2754
 2755    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2756        self.cursor_shape = cursor_shape;
 2757
 2758        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2759        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2760
 2761        cx.notify();
 2762    }
 2763
 2764    pub fn set_current_line_highlight(
 2765        &mut self,
 2766        current_line_highlight: Option<CurrentLineHighlight>,
 2767    ) {
 2768        self.current_line_highlight = current_line_highlight;
 2769    }
 2770
 2771    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2772        self.collapse_matches = collapse_matches;
 2773    }
 2774
 2775    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2776        let buffers = self.buffer.read(cx).all_buffers();
 2777        let Some(project) = self.project.as_ref() else {
 2778            return;
 2779        };
 2780        project.update(cx, |project, cx| {
 2781            for buffer in buffers {
 2782                self.registered_buffers
 2783                    .entry(buffer.read(cx).remote_id())
 2784                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2785            }
 2786        })
 2787    }
 2788
 2789    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2790        if self.collapse_matches {
 2791            return range.start..range.start;
 2792        }
 2793        range.clone()
 2794    }
 2795
 2796    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2797        if self.display_map.read(cx).clip_at_line_ends != clip {
 2798            self.display_map
 2799                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2800        }
 2801    }
 2802
 2803    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2804        self.input_enabled = input_enabled;
 2805    }
 2806
 2807    pub fn set_inline_completions_hidden_for_vim_mode(
 2808        &mut self,
 2809        hidden: bool,
 2810        window: &mut Window,
 2811        cx: &mut Context<Self>,
 2812    ) {
 2813        if hidden != self.inline_completions_hidden_for_vim_mode {
 2814            self.inline_completions_hidden_for_vim_mode = hidden;
 2815            if hidden {
 2816                self.update_visible_inline_completion(window, cx);
 2817            } else {
 2818                self.refresh_inline_completion(true, false, window, cx);
 2819            }
 2820        }
 2821    }
 2822
 2823    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2824        self.menu_inline_completions_policy = value;
 2825    }
 2826
 2827    pub fn set_autoindent(&mut self, autoindent: bool) {
 2828        if autoindent {
 2829            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2830        } else {
 2831            self.autoindent_mode = None;
 2832        }
 2833    }
 2834
 2835    pub fn read_only(&self, cx: &App) -> bool {
 2836        self.read_only || self.buffer.read(cx).read_only()
 2837    }
 2838
 2839    pub fn set_read_only(&mut self, read_only: bool) {
 2840        self.read_only = read_only;
 2841    }
 2842
 2843    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2844        self.use_autoclose = autoclose;
 2845    }
 2846
 2847    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2848        self.use_auto_surround = auto_surround;
 2849    }
 2850
 2851    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2852        self.auto_replace_emoji_shortcode = auto_replace;
 2853    }
 2854
 2855    pub fn toggle_edit_predictions(
 2856        &mut self,
 2857        _: &ToggleEditPrediction,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        if self.show_inline_completions_override.is_some() {
 2862            self.set_show_edit_predictions(None, window, cx);
 2863        } else {
 2864            let show_edit_predictions = !self.edit_predictions_enabled();
 2865            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2866        }
 2867    }
 2868
 2869    pub fn set_show_edit_predictions(
 2870        &mut self,
 2871        show_edit_predictions: Option<bool>,
 2872        window: &mut Window,
 2873        cx: &mut Context<Self>,
 2874    ) {
 2875        self.show_inline_completions_override = show_edit_predictions;
 2876        self.update_edit_prediction_settings(cx);
 2877
 2878        if let Some(false) = show_edit_predictions {
 2879            self.discard_inline_completion(false, cx);
 2880        } else {
 2881            self.refresh_inline_completion(false, true, window, cx);
 2882        }
 2883    }
 2884
 2885    fn inline_completions_disabled_in_scope(
 2886        &self,
 2887        buffer: &Entity<Buffer>,
 2888        buffer_position: language::Anchor,
 2889        cx: &App,
 2890    ) -> bool {
 2891        let snapshot = buffer.read(cx).snapshot();
 2892        let settings = snapshot.settings_at(buffer_position, cx);
 2893
 2894        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2895            return false;
 2896        };
 2897
 2898        scope.override_name().map_or(false, |scope_name| {
 2899            settings
 2900                .edit_predictions_disabled_in
 2901                .iter()
 2902                .any(|s| s == scope_name)
 2903        })
 2904    }
 2905
 2906    pub fn set_use_modal_editing(&mut self, to: bool) {
 2907        self.use_modal_editing = to;
 2908    }
 2909
 2910    pub fn use_modal_editing(&self) -> bool {
 2911        self.use_modal_editing
 2912    }
 2913
 2914    fn selections_did_change(
 2915        &mut self,
 2916        local: bool,
 2917        old_cursor_position: &Anchor,
 2918        effects: SelectionEffects,
 2919        window: &mut Window,
 2920        cx: &mut Context<Self>,
 2921    ) {
 2922        window.invalidate_character_coordinates();
 2923
 2924        // Copy selections to primary selection buffer
 2925        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2926        if local {
 2927            let selections = self.selections.all::<usize>(cx);
 2928            let buffer_handle = self.buffer.read(cx).read(cx);
 2929
 2930            let mut text = String::new();
 2931            for (index, selection) in selections.iter().enumerate() {
 2932                let text_for_selection = buffer_handle
 2933                    .text_for_range(selection.start..selection.end)
 2934                    .collect::<String>();
 2935
 2936                text.push_str(&text_for_selection);
 2937                if index != selections.len() - 1 {
 2938                    text.push('\n');
 2939                }
 2940            }
 2941
 2942            if !text.is_empty() {
 2943                cx.write_to_primary(ClipboardItem::new_string(text));
 2944            }
 2945        }
 2946
 2947        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2948            self.buffer.update(cx, |buffer, cx| {
 2949                buffer.set_active_selections(
 2950                    &self.selections.disjoint_anchors(),
 2951                    self.selections.line_mode,
 2952                    self.cursor_shape,
 2953                    cx,
 2954                )
 2955            });
 2956        }
 2957        let display_map = self
 2958            .display_map
 2959            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2960        let buffer = &display_map.buffer_snapshot;
 2961        if self.selections.count() == 1 {
 2962            self.add_selections_state = None;
 2963        }
 2964        self.select_next_state = None;
 2965        self.select_prev_state = None;
 2966        self.select_syntax_node_history.try_clear();
 2967        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2968        self.snippet_stack
 2969            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2970        self.take_rename(false, window, cx);
 2971
 2972        let newest_selection = self.selections.newest_anchor();
 2973        let new_cursor_position = newest_selection.head();
 2974        let selection_start = newest_selection.start;
 2975
 2976        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2977            self.push_to_nav_history(
 2978                *old_cursor_position,
 2979                Some(new_cursor_position.to_point(buffer)),
 2980                false,
 2981                effects.nav_history == Some(true),
 2982                cx,
 2983            );
 2984        }
 2985
 2986        if local {
 2987            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2988                if !self.registered_buffers.contains_key(&buffer_id) {
 2989                    if let Some(project) = self.project.as_ref() {
 2990                        project.update(cx, |project, cx| {
 2991                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2992                                return;
 2993                            };
 2994                            self.registered_buffers.insert(
 2995                                buffer_id,
 2996                                project.register_buffer_with_language_servers(&buffer, cx),
 2997                            );
 2998                        })
 2999                    }
 3000                }
 3001            }
 3002
 3003            let mut context_menu = self.context_menu.borrow_mut();
 3004            let completion_menu = match context_menu.as_ref() {
 3005                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3006                Some(CodeContextMenu::CodeActions(_)) => {
 3007                    *context_menu = None;
 3008                    None
 3009                }
 3010                None => None,
 3011            };
 3012            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3013            drop(context_menu);
 3014
 3015            if effects.completions {
 3016                if let Some(completion_position) = completion_position {
 3017                    let start_offset = selection_start.to_offset(buffer);
 3018                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3019                    let continue_showing = if position_matches {
 3020                        if self.snippet_stack.is_empty() {
 3021                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3022                        } else {
 3023                            // Snippet choices can be shown even when the cursor is in whitespace.
 3024                            // Dismissing the menu with actions like backspace is handled by
 3025                            // invalidation regions.
 3026                            true
 3027                        }
 3028                    } else {
 3029                        false
 3030                    };
 3031
 3032                    if continue_showing {
 3033                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3034                    } else {
 3035                        self.hide_context_menu(window, cx);
 3036                    }
 3037                }
 3038            }
 3039
 3040            hide_hover(self, cx);
 3041
 3042            if old_cursor_position.to_display_point(&display_map).row()
 3043                != new_cursor_position.to_display_point(&display_map).row()
 3044            {
 3045                self.available_code_actions.take();
 3046            }
 3047            self.refresh_code_actions(window, cx);
 3048            self.refresh_document_highlights(cx);
 3049            self.refresh_selected_text_highlights(false, window, cx);
 3050            refresh_matching_bracket_highlights(self, window, cx);
 3051            self.update_visible_inline_completion(window, cx);
 3052            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3053            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3054            self.inline_blame_popover.take();
 3055            if self.git_blame_inline_enabled {
 3056                self.start_inline_blame_timer(window, cx);
 3057            }
 3058        }
 3059
 3060        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3061        cx.emit(EditorEvent::SelectionsChanged { local });
 3062
 3063        let selections = &self.selections.disjoint;
 3064        if selections.len() == 1 {
 3065            cx.emit(SearchEvent::ActiveMatchChanged)
 3066        }
 3067        if local {
 3068            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3069                let inmemory_selections = selections
 3070                    .iter()
 3071                    .map(|s| {
 3072                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3073                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3074                    })
 3075                    .collect();
 3076                self.update_restoration_data(cx, |data| {
 3077                    data.selections = inmemory_selections;
 3078                });
 3079
 3080                if WorkspaceSettings::get(None, cx).restore_on_startup
 3081                    != RestoreOnStartupBehavior::None
 3082                {
 3083                    if let Some(workspace_id) =
 3084                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3085                    {
 3086                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3087                        let selections = selections.clone();
 3088                        let background_executor = cx.background_executor().clone();
 3089                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3090                        self.serialize_selections = cx.background_spawn(async move {
 3091                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3092                            let db_selections = selections
 3093                                .iter()
 3094                                .map(|selection| {
 3095                                    (
 3096                                        selection.start.to_offset(&snapshot),
 3097                                        selection.end.to_offset(&snapshot),
 3098                                    )
 3099                                })
 3100                                .collect();
 3101
 3102                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3103                                .await
 3104                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3105                                .log_err();
 3106                        });
 3107                    }
 3108                }
 3109            }
 3110        }
 3111
 3112        cx.notify();
 3113    }
 3114
 3115    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3116        use text::ToOffset as _;
 3117        use text::ToPoint as _;
 3118
 3119        if self.mode.is_minimap()
 3120            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3121        {
 3122            return;
 3123        }
 3124
 3125        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3126            return;
 3127        };
 3128
 3129        let snapshot = singleton.read(cx).snapshot();
 3130        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3131            let display_snapshot = display_map.snapshot(cx);
 3132
 3133            display_snapshot
 3134                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3135                .map(|fold| {
 3136                    fold.range.start.text_anchor.to_point(&snapshot)
 3137                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3138                })
 3139                .collect()
 3140        });
 3141        self.update_restoration_data(cx, |data| {
 3142            data.folds = inmemory_folds;
 3143        });
 3144
 3145        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3146            return;
 3147        };
 3148        let background_executor = cx.background_executor().clone();
 3149        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3150        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3151            display_map
 3152                .snapshot(cx)
 3153                .folds_in_range(0..snapshot.len())
 3154                .map(|fold| {
 3155                    (
 3156                        fold.range.start.text_anchor.to_offset(&snapshot),
 3157                        fold.range.end.text_anchor.to_offset(&snapshot),
 3158                    )
 3159                })
 3160                .collect()
 3161        });
 3162        self.serialize_folds = cx.background_spawn(async move {
 3163            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3164            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3165                .await
 3166                .with_context(|| {
 3167                    format!(
 3168                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3169                    )
 3170                })
 3171                .log_err();
 3172        });
 3173    }
 3174
 3175    pub fn sync_selections(
 3176        &mut self,
 3177        other: Entity<Editor>,
 3178        cx: &mut Context<Self>,
 3179    ) -> gpui::Subscription {
 3180        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3181        self.selections.change_with(cx, |selections| {
 3182            selections.select_anchors(other_selections);
 3183        });
 3184
 3185        let other_subscription =
 3186            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3187                EditorEvent::SelectionsChanged { local: true } => {
 3188                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3189                    if other_selections.is_empty() {
 3190                        return;
 3191                    }
 3192                    this.selections.change_with(cx, |selections| {
 3193                        selections.select_anchors(other_selections);
 3194                    });
 3195                }
 3196                _ => {}
 3197            });
 3198
 3199        let this_subscription =
 3200            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3201                EditorEvent::SelectionsChanged { local: true } => {
 3202                    let these_selections = this.selections.disjoint.to_vec();
 3203                    if these_selections.is_empty() {
 3204                        return;
 3205                    }
 3206                    other.update(cx, |other_editor, cx| {
 3207                        other_editor.selections.change_with(cx, |selections| {
 3208                            selections.select_anchors(these_selections);
 3209                        })
 3210                    });
 3211                }
 3212                _ => {}
 3213            });
 3214
 3215        Subscription::join(other_subscription, this_subscription)
 3216    }
 3217
 3218    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3219    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3220    /// effects of selection change occur at the end of the transaction.
 3221    pub fn change_selections<R>(
 3222        &mut self,
 3223        effects: SelectionEffects,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3227    ) -> R {
 3228        if let Some(state) = &mut self.deferred_selection_effects_state {
 3229            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3230            state.effects.completions = effects.completions;
 3231            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3232            let (changed, result) = self.selections.change_with(cx, change);
 3233            state.changed |= changed;
 3234            return result;
 3235        }
 3236        let mut state = DeferredSelectionEffectsState {
 3237            changed: false,
 3238            effects,
 3239            old_cursor_position: self.selections.newest_anchor().head(),
 3240            history_entry: SelectionHistoryEntry {
 3241                selections: self.selections.disjoint_anchors(),
 3242                select_next_state: self.select_next_state.clone(),
 3243                select_prev_state: self.select_prev_state.clone(),
 3244                add_selections_state: self.add_selections_state.clone(),
 3245            },
 3246        };
 3247        let (changed, result) = self.selections.change_with(cx, change);
 3248        state.changed = state.changed || changed;
 3249        if self.defer_selection_effects {
 3250            self.deferred_selection_effects_state = Some(state);
 3251        } else {
 3252            self.apply_selection_effects(state, window, cx);
 3253        }
 3254        result
 3255    }
 3256
 3257    /// Defers the effects of selection change, so that the effects of multiple calls to
 3258    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3259    /// to selection history and the state of popovers based on selection position aren't
 3260    /// erroneously updated.
 3261    pub fn with_selection_effects_deferred<R>(
 3262        &mut self,
 3263        window: &mut Window,
 3264        cx: &mut Context<Self>,
 3265        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3266    ) -> R {
 3267        let already_deferred = self.defer_selection_effects;
 3268        self.defer_selection_effects = true;
 3269        let result = update(self, window, cx);
 3270        if !already_deferred {
 3271            self.defer_selection_effects = false;
 3272            if let Some(state) = self.deferred_selection_effects_state.take() {
 3273                self.apply_selection_effects(state, window, cx);
 3274            }
 3275        }
 3276        result
 3277    }
 3278
 3279    fn apply_selection_effects(
 3280        &mut self,
 3281        state: DeferredSelectionEffectsState,
 3282        window: &mut Window,
 3283        cx: &mut Context<Self>,
 3284    ) {
 3285        if state.changed {
 3286            self.selection_history.push(state.history_entry);
 3287
 3288            if let Some(autoscroll) = state.effects.scroll {
 3289                self.request_autoscroll(autoscroll, cx);
 3290            }
 3291
 3292            let old_cursor_position = &state.old_cursor_position;
 3293
 3294            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3295
 3296            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3297                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3298            }
 3299        }
 3300    }
 3301
 3302    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3303    where
 3304        I: IntoIterator<Item = (Range<S>, T)>,
 3305        S: ToOffset,
 3306        T: Into<Arc<str>>,
 3307    {
 3308        if self.read_only(cx) {
 3309            return;
 3310        }
 3311
 3312        self.buffer
 3313            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3314    }
 3315
 3316    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3317    where
 3318        I: IntoIterator<Item = (Range<S>, T)>,
 3319        S: ToOffset,
 3320        T: Into<Arc<str>>,
 3321    {
 3322        if self.read_only(cx) {
 3323            return;
 3324        }
 3325
 3326        self.buffer.update(cx, |buffer, cx| {
 3327            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3328        });
 3329    }
 3330
 3331    pub fn edit_with_block_indent<I, S, T>(
 3332        &mut self,
 3333        edits: I,
 3334        original_indent_columns: Vec<Option<u32>>,
 3335        cx: &mut Context<Self>,
 3336    ) where
 3337        I: IntoIterator<Item = (Range<S>, T)>,
 3338        S: ToOffset,
 3339        T: Into<Arc<str>>,
 3340    {
 3341        if self.read_only(cx) {
 3342            return;
 3343        }
 3344
 3345        self.buffer.update(cx, |buffer, cx| {
 3346            buffer.edit(
 3347                edits,
 3348                Some(AutoindentMode::Block {
 3349                    original_indent_columns,
 3350                }),
 3351                cx,
 3352            )
 3353        });
 3354    }
 3355
 3356    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3357        self.hide_context_menu(window, cx);
 3358
 3359        match phase {
 3360            SelectPhase::Begin {
 3361                position,
 3362                add,
 3363                click_count,
 3364            } => self.begin_selection(position, add, click_count, window, cx),
 3365            SelectPhase::BeginColumnar {
 3366                position,
 3367                goal_column,
 3368                reset,
 3369                mode,
 3370            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3371            SelectPhase::Extend {
 3372                position,
 3373                click_count,
 3374            } => self.extend_selection(position, click_count, window, cx),
 3375            SelectPhase::Update {
 3376                position,
 3377                goal_column,
 3378                scroll_delta,
 3379            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3380            SelectPhase::End => self.end_selection(window, cx),
 3381        }
 3382    }
 3383
 3384    fn extend_selection(
 3385        &mut self,
 3386        position: DisplayPoint,
 3387        click_count: usize,
 3388        window: &mut Window,
 3389        cx: &mut Context<Self>,
 3390    ) {
 3391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3392        let tail = self.selections.newest::<usize>(cx).tail();
 3393        self.begin_selection(position, false, click_count, window, cx);
 3394
 3395        let position = position.to_offset(&display_map, Bias::Left);
 3396        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3397
 3398        let mut pending_selection = self
 3399            .selections
 3400            .pending_anchor()
 3401            .expect("extend_selection not called with pending selection");
 3402        if position >= tail {
 3403            pending_selection.start = tail_anchor;
 3404        } else {
 3405            pending_selection.end = tail_anchor;
 3406            pending_selection.reversed = true;
 3407        }
 3408
 3409        let mut pending_mode = self.selections.pending_mode().unwrap();
 3410        match &mut pending_mode {
 3411            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3412            _ => {}
 3413        }
 3414
 3415        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3416            SelectionEffects::scroll(Autoscroll::fit())
 3417        } else {
 3418            SelectionEffects::no_scroll()
 3419        };
 3420
 3421        self.change_selections(effects, window, cx, |s| {
 3422            s.set_pending(pending_selection, pending_mode)
 3423        });
 3424    }
 3425
 3426    fn begin_selection(
 3427        &mut self,
 3428        position: DisplayPoint,
 3429        add: bool,
 3430        click_count: usize,
 3431        window: &mut Window,
 3432        cx: &mut Context<Self>,
 3433    ) {
 3434        if !self.focus_handle.is_focused(window) {
 3435            self.last_focused_descendant = None;
 3436            window.focus(&self.focus_handle);
 3437        }
 3438
 3439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3440        let buffer = &display_map.buffer_snapshot;
 3441        let position = display_map.clip_point(position, Bias::Left);
 3442
 3443        let start;
 3444        let end;
 3445        let mode;
 3446        let mut auto_scroll;
 3447        match click_count {
 3448            1 => {
 3449                start = buffer.anchor_before(position.to_point(&display_map));
 3450                end = start;
 3451                mode = SelectMode::Character;
 3452                auto_scroll = true;
 3453            }
 3454            2 => {
 3455                let position = display_map
 3456                    .clip_point(position, Bias::Left)
 3457                    .to_offset(&display_map, Bias::Left);
 3458                let (range, _) = buffer.surrounding_word(position, false);
 3459                start = buffer.anchor_before(range.start);
 3460                end = buffer.anchor_before(range.end);
 3461                mode = SelectMode::Word(start..end);
 3462                auto_scroll = true;
 3463            }
 3464            3 => {
 3465                let position = display_map
 3466                    .clip_point(position, Bias::Left)
 3467                    .to_point(&display_map);
 3468                let line_start = display_map.prev_line_boundary(position).0;
 3469                let next_line_start = buffer.clip_point(
 3470                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3471                    Bias::Left,
 3472                );
 3473                start = buffer.anchor_before(line_start);
 3474                end = buffer.anchor_before(next_line_start);
 3475                mode = SelectMode::Line(start..end);
 3476                auto_scroll = true;
 3477            }
 3478            _ => {
 3479                start = buffer.anchor_before(0);
 3480                end = buffer.anchor_before(buffer.len());
 3481                mode = SelectMode::All;
 3482                auto_scroll = false;
 3483            }
 3484        }
 3485        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3486
 3487        let point_to_delete: Option<usize> = {
 3488            let selected_points: Vec<Selection<Point>> =
 3489                self.selections.disjoint_in_range(start..end, cx);
 3490
 3491            if !add || click_count > 1 {
 3492                None
 3493            } else if !selected_points.is_empty() {
 3494                Some(selected_points[0].id)
 3495            } else {
 3496                let clicked_point_already_selected =
 3497                    self.selections.disjoint.iter().find(|selection| {
 3498                        selection.start.to_point(buffer) == start.to_point(buffer)
 3499                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3500                    });
 3501
 3502                clicked_point_already_selected.map(|selection| selection.id)
 3503            }
 3504        };
 3505
 3506        let selections_count = self.selections.count();
 3507        let effects = if auto_scroll {
 3508            SelectionEffects::default()
 3509        } else {
 3510            SelectionEffects::no_scroll()
 3511        };
 3512
 3513        self.change_selections(effects, window, cx, |s| {
 3514            if let Some(point_to_delete) = point_to_delete {
 3515                s.delete(point_to_delete);
 3516
 3517                if selections_count == 1 {
 3518                    s.set_pending_anchor_range(start..end, mode);
 3519                }
 3520            } else {
 3521                if !add {
 3522                    s.clear_disjoint();
 3523                }
 3524
 3525                s.set_pending_anchor_range(start..end, mode);
 3526            }
 3527        });
 3528    }
 3529
 3530    fn begin_columnar_selection(
 3531        &mut self,
 3532        position: DisplayPoint,
 3533        goal_column: u32,
 3534        reset: bool,
 3535        mode: ColumnarMode,
 3536        window: &mut Window,
 3537        cx: &mut Context<Self>,
 3538    ) {
 3539        if !self.focus_handle.is_focused(window) {
 3540            self.last_focused_descendant = None;
 3541            window.focus(&self.focus_handle);
 3542        }
 3543
 3544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3545
 3546        if reset {
 3547            let pointer_position = display_map
 3548                .buffer_snapshot
 3549                .anchor_before(position.to_point(&display_map));
 3550
 3551            self.change_selections(
 3552                SelectionEffects::scroll(Autoscroll::newest()),
 3553                window,
 3554                cx,
 3555                |s| {
 3556                    s.clear_disjoint();
 3557                    s.set_pending_anchor_range(
 3558                        pointer_position..pointer_position,
 3559                        SelectMode::Character,
 3560                    );
 3561                },
 3562            );
 3563        };
 3564
 3565        let tail = self.selections.newest::<Point>(cx).tail();
 3566        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3567        self.columnar_selection_state = match mode {
 3568            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3569                selection_tail: selection_anchor,
 3570                display_point: if reset {
 3571                    if position.column() != goal_column {
 3572                        Some(DisplayPoint::new(position.row(), goal_column))
 3573                    } else {
 3574                        None
 3575                    }
 3576                } else {
 3577                    None
 3578                },
 3579            }),
 3580            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3581                selection_tail: selection_anchor,
 3582            }),
 3583        };
 3584
 3585        if !reset {
 3586            self.select_columns(position, goal_column, &display_map, window, cx);
 3587        }
 3588    }
 3589
 3590    fn update_selection(
 3591        &mut self,
 3592        position: DisplayPoint,
 3593        goal_column: u32,
 3594        scroll_delta: gpui::Point<f32>,
 3595        window: &mut Window,
 3596        cx: &mut Context<Self>,
 3597    ) {
 3598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3599
 3600        if self.columnar_selection_state.is_some() {
 3601            self.select_columns(position, goal_column, &display_map, window, cx);
 3602        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3603            let buffer = &display_map.buffer_snapshot;
 3604            let head;
 3605            let tail;
 3606            let mode = self.selections.pending_mode().unwrap();
 3607            match &mode {
 3608                SelectMode::Character => {
 3609                    head = position.to_point(&display_map);
 3610                    tail = pending.tail().to_point(buffer);
 3611                }
 3612                SelectMode::Word(original_range) => {
 3613                    let offset = display_map
 3614                        .clip_point(position, Bias::Left)
 3615                        .to_offset(&display_map, Bias::Left);
 3616                    let original_range = original_range.to_offset(buffer);
 3617
 3618                    let head_offset = if buffer.is_inside_word(offset, false)
 3619                        || original_range.contains(&offset)
 3620                    {
 3621                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3622                        if word_range.start < original_range.start {
 3623                            word_range.start
 3624                        } else {
 3625                            word_range.end
 3626                        }
 3627                    } else {
 3628                        offset
 3629                    };
 3630
 3631                    head = head_offset.to_point(buffer);
 3632                    if head_offset <= original_range.start {
 3633                        tail = original_range.end.to_point(buffer);
 3634                    } else {
 3635                        tail = original_range.start.to_point(buffer);
 3636                    }
 3637                }
 3638                SelectMode::Line(original_range) => {
 3639                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3640
 3641                    let position = display_map
 3642                        .clip_point(position, Bias::Left)
 3643                        .to_point(&display_map);
 3644                    let line_start = display_map.prev_line_boundary(position).0;
 3645                    let next_line_start = buffer.clip_point(
 3646                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3647                        Bias::Left,
 3648                    );
 3649
 3650                    if line_start < original_range.start {
 3651                        head = line_start
 3652                    } else {
 3653                        head = next_line_start
 3654                    }
 3655
 3656                    if head <= original_range.start {
 3657                        tail = original_range.end;
 3658                    } else {
 3659                        tail = original_range.start;
 3660                    }
 3661                }
 3662                SelectMode::All => {
 3663                    return;
 3664                }
 3665            };
 3666
 3667            if head < tail {
 3668                pending.start = buffer.anchor_before(head);
 3669                pending.end = buffer.anchor_before(tail);
 3670                pending.reversed = true;
 3671            } else {
 3672                pending.start = buffer.anchor_before(tail);
 3673                pending.end = buffer.anchor_before(head);
 3674                pending.reversed = false;
 3675            }
 3676
 3677            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3678                s.set_pending(pending, mode);
 3679            });
 3680        } else {
 3681            log::error!("update_selection dispatched with no pending selection");
 3682            return;
 3683        }
 3684
 3685        self.apply_scroll_delta(scroll_delta, window, cx);
 3686        cx.notify();
 3687    }
 3688
 3689    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3690        self.columnar_selection_state.take();
 3691        if self.selections.pending_anchor().is_some() {
 3692            let selections = self.selections.all::<usize>(cx);
 3693            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3694                s.select(selections);
 3695                s.clear_pending();
 3696            });
 3697        }
 3698    }
 3699
 3700    fn select_columns(
 3701        &mut self,
 3702        head: DisplayPoint,
 3703        goal_column: u32,
 3704        display_map: &DisplaySnapshot,
 3705        window: &mut Window,
 3706        cx: &mut Context<Self>,
 3707    ) {
 3708        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3709            return;
 3710        };
 3711
 3712        let tail = match columnar_state {
 3713            ColumnarSelectionState::FromMouse {
 3714                selection_tail,
 3715                display_point,
 3716            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3717            ColumnarSelectionState::FromSelection { selection_tail } => {
 3718                selection_tail.to_display_point(&display_map)
 3719            }
 3720        };
 3721
 3722        let start_row = cmp::min(tail.row(), head.row());
 3723        let end_row = cmp::max(tail.row(), head.row());
 3724        let start_column = cmp::min(tail.column(), goal_column);
 3725        let end_column = cmp::max(tail.column(), goal_column);
 3726        let reversed = start_column < tail.column();
 3727
 3728        let selection_ranges = (start_row.0..=end_row.0)
 3729            .map(DisplayRow)
 3730            .filter_map(|row| {
 3731                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3732                    || start_column <= display_map.line_len(row))
 3733                    && !display_map.is_block_line(row)
 3734                {
 3735                    let start = display_map
 3736                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3737                        .to_point(display_map);
 3738                    let end = display_map
 3739                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3740                        .to_point(display_map);
 3741                    if reversed {
 3742                        Some(end..start)
 3743                    } else {
 3744                        Some(start..end)
 3745                    }
 3746                } else {
 3747                    None
 3748                }
 3749            })
 3750            .collect::<Vec<_>>();
 3751
 3752        let ranges = match columnar_state {
 3753            ColumnarSelectionState::FromMouse { .. } => {
 3754                let mut non_empty_ranges = selection_ranges
 3755                    .iter()
 3756                    .filter(|selection_range| selection_range.start != selection_range.end)
 3757                    .peekable();
 3758                if non_empty_ranges.peek().is_some() {
 3759                    non_empty_ranges.cloned().collect()
 3760                } else {
 3761                    selection_ranges
 3762                }
 3763            }
 3764            _ => selection_ranges,
 3765        };
 3766
 3767        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3768            s.select_ranges(ranges);
 3769        });
 3770        cx.notify();
 3771    }
 3772
 3773    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3774        self.selections
 3775            .all_adjusted(cx)
 3776            .iter()
 3777            .any(|selection| !selection.is_empty())
 3778    }
 3779
 3780    pub fn has_pending_nonempty_selection(&self) -> bool {
 3781        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3782            Some(Selection { start, end, .. }) => start != end,
 3783            None => false,
 3784        };
 3785
 3786        pending_nonempty_selection
 3787            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3788    }
 3789
 3790    pub fn has_pending_selection(&self) -> bool {
 3791        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3792    }
 3793
 3794    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3795        self.selection_mark_mode = false;
 3796        self.selection_drag_state = SelectionDragState::None;
 3797
 3798        if self.clear_expanded_diff_hunks(cx) {
 3799            cx.notify();
 3800            return;
 3801        }
 3802        if self.dismiss_menus_and_popups(true, window, cx) {
 3803            return;
 3804        }
 3805
 3806        if self.mode.is_full()
 3807            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3808        {
 3809            return;
 3810        }
 3811
 3812        cx.propagate();
 3813    }
 3814
 3815    pub fn dismiss_menus_and_popups(
 3816        &mut self,
 3817        is_user_requested: bool,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) -> bool {
 3821        if self.take_rename(false, window, cx).is_some() {
 3822            return true;
 3823        }
 3824
 3825        if hide_hover(self, cx) {
 3826            return true;
 3827        }
 3828
 3829        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3830            return true;
 3831        }
 3832
 3833        if self.hide_context_menu(window, cx).is_some() {
 3834            return true;
 3835        }
 3836
 3837        if self.mouse_context_menu.take().is_some() {
 3838            return true;
 3839        }
 3840
 3841        if is_user_requested && self.discard_inline_completion(true, cx) {
 3842            return true;
 3843        }
 3844
 3845        if self.snippet_stack.pop().is_some() {
 3846            return true;
 3847        }
 3848
 3849        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3850            self.dismiss_diagnostics(cx);
 3851            return true;
 3852        }
 3853
 3854        false
 3855    }
 3856
 3857    fn linked_editing_ranges_for(
 3858        &self,
 3859        selection: Range<text::Anchor>,
 3860        cx: &App,
 3861    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3862        if self.linked_edit_ranges.is_empty() {
 3863            return None;
 3864        }
 3865        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3866            selection.end.buffer_id.and_then(|end_buffer_id| {
 3867                if selection.start.buffer_id != Some(end_buffer_id) {
 3868                    return None;
 3869                }
 3870                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3871                let snapshot = buffer.read(cx).snapshot();
 3872                self.linked_edit_ranges
 3873                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3874                    .map(|ranges| (ranges, snapshot, buffer))
 3875            })?;
 3876        use text::ToOffset as TO;
 3877        // find offset from the start of current range to current cursor position
 3878        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3879
 3880        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3881        let start_difference = start_offset - start_byte_offset;
 3882        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3883        let end_difference = end_offset - start_byte_offset;
 3884        // Current range has associated linked ranges.
 3885        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3886        for range in linked_ranges.iter() {
 3887            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3888            let end_offset = start_offset + end_difference;
 3889            let start_offset = start_offset + start_difference;
 3890            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3891                continue;
 3892            }
 3893            if self.selections.disjoint_anchor_ranges().any(|s| {
 3894                if s.start.buffer_id != selection.start.buffer_id
 3895                    || s.end.buffer_id != selection.end.buffer_id
 3896                {
 3897                    return false;
 3898                }
 3899                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3900                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3901            }) {
 3902                continue;
 3903            }
 3904            let start = buffer_snapshot.anchor_after(start_offset);
 3905            let end = buffer_snapshot.anchor_after(end_offset);
 3906            linked_edits
 3907                .entry(buffer.clone())
 3908                .or_default()
 3909                .push(start..end);
 3910        }
 3911        Some(linked_edits)
 3912    }
 3913
 3914    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3915        let text: Arc<str> = text.into();
 3916
 3917        if self.read_only(cx) {
 3918            return;
 3919        }
 3920
 3921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3922
 3923        let selections = self.selections.all_adjusted(cx);
 3924        let mut bracket_inserted = false;
 3925        let mut edits = Vec::new();
 3926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3927        let mut new_selections = Vec::with_capacity(selections.len());
 3928        let mut new_autoclose_regions = Vec::new();
 3929        let snapshot = self.buffer.read(cx).read(cx);
 3930        let mut clear_linked_edit_ranges = false;
 3931
 3932        for (selection, autoclose_region) in
 3933            self.selections_with_autoclose_regions(selections, &snapshot)
 3934        {
 3935            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3936                // Determine if the inserted text matches the opening or closing
 3937                // bracket of any of this language's bracket pairs.
 3938                let mut bracket_pair = None;
 3939                let mut is_bracket_pair_start = false;
 3940                let mut is_bracket_pair_end = false;
 3941                if !text.is_empty() {
 3942                    let mut bracket_pair_matching_end = None;
 3943                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3944                    //  and they are removing the character that triggered IME popup.
 3945                    for (pair, enabled) in scope.brackets() {
 3946                        if !pair.close && !pair.surround {
 3947                            continue;
 3948                        }
 3949
 3950                        if enabled && pair.start.ends_with(text.as_ref()) {
 3951                            let prefix_len = pair.start.len() - text.len();
 3952                            let preceding_text_matches_prefix = prefix_len == 0
 3953                                || (selection.start.column >= (prefix_len as u32)
 3954                                    && snapshot.contains_str_at(
 3955                                        Point::new(
 3956                                            selection.start.row,
 3957                                            selection.start.column - (prefix_len as u32),
 3958                                        ),
 3959                                        &pair.start[..prefix_len],
 3960                                    ));
 3961                            if preceding_text_matches_prefix {
 3962                                bracket_pair = Some(pair.clone());
 3963                                is_bracket_pair_start = true;
 3964                                break;
 3965                            }
 3966                        }
 3967                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3968                        {
 3969                            // take first bracket pair matching end, but don't break in case a later bracket
 3970                            // pair matches start
 3971                            bracket_pair_matching_end = Some(pair.clone());
 3972                        }
 3973                    }
 3974                    if let Some(end) = bracket_pair_matching_end
 3975                        && bracket_pair.is_none()
 3976                    {
 3977                        bracket_pair = Some(end);
 3978                        is_bracket_pair_end = true;
 3979                    }
 3980                }
 3981
 3982                if let Some(bracket_pair) = bracket_pair {
 3983                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3984                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3985                    let auto_surround =
 3986                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3987                    if selection.is_empty() {
 3988                        if is_bracket_pair_start {
 3989                            // If the inserted text is a suffix of an opening bracket and the
 3990                            // selection is preceded by the rest of the opening bracket, then
 3991                            // insert the closing bracket.
 3992                            let following_text_allows_autoclose = snapshot
 3993                                .chars_at(selection.start)
 3994                                .next()
 3995                                .map_or(true, |c| scope.should_autoclose_before(c));
 3996
 3997                            let preceding_text_allows_autoclose = selection.start.column == 0
 3998                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3999                                    true,
 4000                                    |c| {
 4001                                        bracket_pair.start != bracket_pair.end
 4002                                            || !snapshot
 4003                                                .char_classifier_at(selection.start)
 4004                                                .is_word(c)
 4005                                    },
 4006                                );
 4007
 4008                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4009                                && bracket_pair.start.len() == 1
 4010                            {
 4011                                let target = bracket_pair.start.chars().next().unwrap();
 4012                                let current_line_count = snapshot
 4013                                    .reversed_chars_at(selection.start)
 4014                                    .take_while(|&c| c != '\n')
 4015                                    .filter(|&c| c == target)
 4016                                    .count();
 4017                                current_line_count % 2 == 1
 4018                            } else {
 4019                                false
 4020                            };
 4021
 4022                            if autoclose
 4023                                && bracket_pair.close
 4024                                && following_text_allows_autoclose
 4025                                && preceding_text_allows_autoclose
 4026                                && !is_closing_quote
 4027                            {
 4028                                let anchor = snapshot.anchor_before(selection.end);
 4029                                new_selections.push((selection.map(|_| anchor), text.len()));
 4030                                new_autoclose_regions.push((
 4031                                    anchor,
 4032                                    text.len(),
 4033                                    selection.id,
 4034                                    bracket_pair.clone(),
 4035                                ));
 4036                                edits.push((
 4037                                    selection.range(),
 4038                                    format!("{}{}", text, bracket_pair.end).into(),
 4039                                ));
 4040                                bracket_inserted = true;
 4041                                continue;
 4042                            }
 4043                        }
 4044
 4045                        if let Some(region) = autoclose_region {
 4046                            // If the selection is followed by an auto-inserted closing bracket,
 4047                            // then don't insert that closing bracket again; just move the selection
 4048                            // past the closing bracket.
 4049                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4050                                && text.as_ref() == region.pair.end.as_str();
 4051                            if should_skip {
 4052                                let anchor = snapshot.anchor_after(selection.end);
 4053                                new_selections
 4054                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4055                                continue;
 4056                            }
 4057                        }
 4058
 4059                        let always_treat_brackets_as_autoclosed = snapshot
 4060                            .language_settings_at(selection.start, cx)
 4061                            .always_treat_brackets_as_autoclosed;
 4062                        if always_treat_brackets_as_autoclosed
 4063                            && is_bracket_pair_end
 4064                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4065                        {
 4066                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4067                            // and the inserted text is a closing bracket and the selection is followed
 4068                            // by the closing bracket then move the selection past the closing bracket.
 4069                            let anchor = snapshot.anchor_after(selection.end);
 4070                            new_selections.push((selection.map(|_| anchor), text.len()));
 4071                            continue;
 4072                        }
 4073                    }
 4074                    // If an opening bracket is 1 character long and is typed while
 4075                    // text is selected, then surround that text with the bracket pair.
 4076                    else if auto_surround
 4077                        && bracket_pair.surround
 4078                        && is_bracket_pair_start
 4079                        && bracket_pair.start.chars().count() == 1
 4080                    {
 4081                        edits.push((selection.start..selection.start, text.clone()));
 4082                        edits.push((
 4083                            selection.end..selection.end,
 4084                            bracket_pair.end.as_str().into(),
 4085                        ));
 4086                        bracket_inserted = true;
 4087                        new_selections.push((
 4088                            Selection {
 4089                                id: selection.id,
 4090                                start: snapshot.anchor_after(selection.start),
 4091                                end: snapshot.anchor_before(selection.end),
 4092                                reversed: selection.reversed,
 4093                                goal: selection.goal,
 4094                            },
 4095                            0,
 4096                        ));
 4097                        continue;
 4098                    }
 4099                }
 4100            }
 4101
 4102            if self.auto_replace_emoji_shortcode
 4103                && selection.is_empty()
 4104                && text.as_ref().ends_with(':')
 4105            {
 4106                if let Some(possible_emoji_short_code) =
 4107                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4108                {
 4109                    if !possible_emoji_short_code.is_empty() {
 4110                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4111                            let emoji_shortcode_start = Point::new(
 4112                                selection.start.row,
 4113                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4114                            );
 4115
 4116                            // Remove shortcode from buffer
 4117                            edits.push((
 4118                                emoji_shortcode_start..selection.start,
 4119                                "".to_string().into(),
 4120                            ));
 4121                            new_selections.push((
 4122                                Selection {
 4123                                    id: selection.id,
 4124                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4125                                    end: snapshot.anchor_before(selection.start),
 4126                                    reversed: selection.reversed,
 4127                                    goal: selection.goal,
 4128                                },
 4129                                0,
 4130                            ));
 4131
 4132                            // Insert emoji
 4133                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4134                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4135                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4136
 4137                            continue;
 4138                        }
 4139                    }
 4140                }
 4141            }
 4142
 4143            // If not handling any auto-close operation, then just replace the selected
 4144            // text with the given input and move the selection to the end of the
 4145            // newly inserted text.
 4146            let anchor = snapshot.anchor_after(selection.end);
 4147            if !self.linked_edit_ranges.is_empty() {
 4148                let start_anchor = snapshot.anchor_before(selection.start);
 4149
 4150                let is_word_char = text.chars().next().map_or(true, |char| {
 4151                    let classifier = snapshot
 4152                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4153                        .ignore_punctuation(true);
 4154                    classifier.is_word(char)
 4155                });
 4156
 4157                if is_word_char {
 4158                    if let Some(ranges) = self
 4159                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4160                    {
 4161                        for (buffer, edits) in ranges {
 4162                            linked_edits
 4163                                .entry(buffer.clone())
 4164                                .or_default()
 4165                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4166                        }
 4167                    }
 4168                } else {
 4169                    clear_linked_edit_ranges = true;
 4170                }
 4171            }
 4172
 4173            new_selections.push((selection.map(|_| anchor), 0));
 4174            edits.push((selection.start..selection.end, text.clone()));
 4175        }
 4176
 4177        drop(snapshot);
 4178
 4179        self.transact(window, cx, |this, window, cx| {
 4180            if clear_linked_edit_ranges {
 4181                this.linked_edit_ranges.clear();
 4182            }
 4183            let initial_buffer_versions =
 4184                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4185
 4186            this.buffer.update(cx, |buffer, cx| {
 4187                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4188            });
 4189            for (buffer, edits) in linked_edits {
 4190                buffer.update(cx, |buffer, cx| {
 4191                    let snapshot = buffer.snapshot();
 4192                    let edits = edits
 4193                        .into_iter()
 4194                        .map(|(range, text)| {
 4195                            use text::ToPoint as TP;
 4196                            let end_point = TP::to_point(&range.end, &snapshot);
 4197                            let start_point = TP::to_point(&range.start, &snapshot);
 4198                            (start_point..end_point, text)
 4199                        })
 4200                        .sorted_by_key(|(range, _)| range.start);
 4201                    buffer.edit(edits, None, cx);
 4202                })
 4203            }
 4204            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4205            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4206            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4207            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4208                .zip(new_selection_deltas)
 4209                .map(|(selection, delta)| Selection {
 4210                    id: selection.id,
 4211                    start: selection.start + delta,
 4212                    end: selection.end + delta,
 4213                    reversed: selection.reversed,
 4214                    goal: SelectionGoal::None,
 4215                })
 4216                .collect::<Vec<_>>();
 4217
 4218            let mut i = 0;
 4219            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4220                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4221                let start = map.buffer_snapshot.anchor_before(position);
 4222                let end = map.buffer_snapshot.anchor_after(position);
 4223                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4224                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4225                        Ordering::Less => i += 1,
 4226                        Ordering::Greater => break,
 4227                        Ordering::Equal => {
 4228                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4229                                Ordering::Less => i += 1,
 4230                                Ordering::Equal => break,
 4231                                Ordering::Greater => break,
 4232                            }
 4233                        }
 4234                    }
 4235                }
 4236                this.autoclose_regions.insert(
 4237                    i,
 4238                    AutocloseRegion {
 4239                        selection_id,
 4240                        range: start..end,
 4241                        pair,
 4242                    },
 4243                );
 4244            }
 4245
 4246            let had_active_inline_completion = this.has_active_inline_completion();
 4247            this.change_selections(
 4248                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4249                window,
 4250                cx,
 4251                |s| s.select(new_selections),
 4252            );
 4253
 4254            if !bracket_inserted {
 4255                if let Some(on_type_format_task) =
 4256                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4257                {
 4258                    on_type_format_task.detach_and_log_err(cx);
 4259                }
 4260            }
 4261
 4262            let editor_settings = EditorSettings::get_global(cx);
 4263            if bracket_inserted
 4264                && (editor_settings.auto_signature_help
 4265                    || editor_settings.show_signature_help_after_edits)
 4266            {
 4267                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4268            }
 4269
 4270            let trigger_in_words =
 4271                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4272            if this.hard_wrap.is_some() {
 4273                let latest: Range<Point> = this.selections.newest(cx).range();
 4274                if latest.is_empty()
 4275                    && this
 4276                        .buffer()
 4277                        .read(cx)
 4278                        .snapshot(cx)
 4279                        .line_len(MultiBufferRow(latest.start.row))
 4280                        == latest.start.column
 4281                {
 4282                    this.rewrap_impl(
 4283                        RewrapOptions {
 4284                            override_language_settings: true,
 4285                            preserve_existing_whitespace: true,
 4286                        },
 4287                        cx,
 4288                    )
 4289                }
 4290            }
 4291            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4292            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4293            this.refresh_inline_completion(true, false, window, cx);
 4294            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4295        });
 4296    }
 4297
 4298    fn find_possible_emoji_shortcode_at_position(
 4299        snapshot: &MultiBufferSnapshot,
 4300        position: Point,
 4301    ) -> Option<String> {
 4302        let mut chars = Vec::new();
 4303        let mut found_colon = false;
 4304        for char in snapshot.reversed_chars_at(position).take(100) {
 4305            // Found a possible emoji shortcode in the middle of the buffer
 4306            if found_colon {
 4307                if char.is_whitespace() {
 4308                    chars.reverse();
 4309                    return Some(chars.iter().collect());
 4310                }
 4311                // If the previous character is not a whitespace, we are in the middle of a word
 4312                // and we only want to complete the shortcode if the word is made up of other emojis
 4313                let mut containing_word = String::new();
 4314                for ch in snapshot
 4315                    .reversed_chars_at(position)
 4316                    .skip(chars.len() + 1)
 4317                    .take(100)
 4318                {
 4319                    if ch.is_whitespace() {
 4320                        break;
 4321                    }
 4322                    containing_word.push(ch);
 4323                }
 4324                let containing_word = containing_word.chars().rev().collect::<String>();
 4325                if util::word_consists_of_emojis(containing_word.as_str()) {
 4326                    chars.reverse();
 4327                    return Some(chars.iter().collect());
 4328                }
 4329            }
 4330
 4331            if char.is_whitespace() || !char.is_ascii() {
 4332                return None;
 4333            }
 4334            if char == ':' {
 4335                found_colon = true;
 4336            } else {
 4337                chars.push(char);
 4338            }
 4339        }
 4340        // Found a possible emoji shortcode at the beginning of the buffer
 4341        chars.reverse();
 4342        Some(chars.iter().collect())
 4343    }
 4344
 4345    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4347        self.transact(window, cx, |this, window, cx| {
 4348            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4349                let selections = this.selections.all::<usize>(cx);
 4350                let multi_buffer = this.buffer.read(cx);
 4351                let buffer = multi_buffer.snapshot(cx);
 4352                selections
 4353                    .iter()
 4354                    .map(|selection| {
 4355                        let start_point = selection.start.to_point(&buffer);
 4356                        let mut existing_indent =
 4357                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4358                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4359                        let start = selection.start;
 4360                        let end = selection.end;
 4361                        let selection_is_empty = start == end;
 4362                        let language_scope = buffer.language_scope_at(start);
 4363                        let (
 4364                            comment_delimiter,
 4365                            doc_delimiter,
 4366                            insert_extra_newline,
 4367                            indent_on_newline,
 4368                            indent_on_extra_newline,
 4369                        ) = if let Some(language) = &language_scope {
 4370                            let mut insert_extra_newline =
 4371                                insert_extra_newline_brackets(&buffer, start..end, language)
 4372                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4373
 4374                            // Comment extension on newline is allowed only for cursor selections
 4375                            let comment_delimiter = maybe!({
 4376                                if !selection_is_empty {
 4377                                    return None;
 4378                                }
 4379
 4380                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4381                                    return None;
 4382                                }
 4383
 4384                                let delimiters = language.line_comment_prefixes();
 4385                                let max_len_of_delimiter =
 4386                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4387                                let (snapshot, range) =
 4388                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4389
 4390                                let num_of_whitespaces = snapshot
 4391                                    .chars_for_range(range.clone())
 4392                                    .take_while(|c| c.is_whitespace())
 4393                                    .count();
 4394                                let comment_candidate = snapshot
 4395                                    .chars_for_range(range.clone())
 4396                                    .skip(num_of_whitespaces)
 4397                                    .take(max_len_of_delimiter)
 4398                                    .collect::<String>();
 4399                                let (delimiter, trimmed_len) = delimiters
 4400                                    .iter()
 4401                                    .filter_map(|delimiter| {
 4402                                        let prefix = delimiter.trim_end();
 4403                                        if comment_candidate.starts_with(prefix) {
 4404                                            Some((delimiter, prefix.len()))
 4405                                        } else {
 4406                                            None
 4407                                        }
 4408                                    })
 4409                                    .max_by_key(|(_, len)| *len)?;
 4410
 4411                                if let Some(BlockCommentConfig {
 4412                                    start: block_start, ..
 4413                                }) = language.block_comment()
 4414                                {
 4415                                    let block_start_trimmed = block_start.trim_end();
 4416                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4417                                        let line_content = snapshot
 4418                                            .chars_for_range(range)
 4419                                            .skip(num_of_whitespaces)
 4420                                            .take(block_start_trimmed.len())
 4421                                            .collect::<String>();
 4422
 4423                                        if line_content.starts_with(block_start_trimmed) {
 4424                                            return None;
 4425                                        }
 4426                                    }
 4427                                }
 4428
 4429                                let cursor_is_placed_after_comment_marker =
 4430                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4431                                if cursor_is_placed_after_comment_marker {
 4432                                    Some(delimiter.clone())
 4433                                } else {
 4434                                    None
 4435                                }
 4436                            });
 4437
 4438                            let mut indent_on_newline = IndentSize::spaces(0);
 4439                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4440
 4441                            let doc_delimiter = maybe!({
 4442                                if !selection_is_empty {
 4443                                    return None;
 4444                                }
 4445
 4446                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4447                                    return None;
 4448                                }
 4449
 4450                                let BlockCommentConfig {
 4451                                    start: start_tag,
 4452                                    end: end_tag,
 4453                                    prefix: delimiter,
 4454                                    tab_size: len,
 4455                                } = language.documentation_comment()?;
 4456                                let is_within_block_comment = buffer
 4457                                    .language_scope_at(start_point)
 4458                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4459                                if !is_within_block_comment {
 4460                                    return None;
 4461                                }
 4462
 4463                                let (snapshot, range) =
 4464                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4465
 4466                                let num_of_whitespaces = snapshot
 4467                                    .chars_for_range(range.clone())
 4468                                    .take_while(|c| c.is_whitespace())
 4469                                    .count();
 4470
 4471                                // 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.
 4472                                let column = start_point.column;
 4473                                let cursor_is_after_start_tag = {
 4474                                    let start_tag_len = start_tag.len();
 4475                                    let start_tag_line = snapshot
 4476                                        .chars_for_range(range.clone())
 4477                                        .skip(num_of_whitespaces)
 4478                                        .take(start_tag_len)
 4479                                        .collect::<String>();
 4480                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4481                                        num_of_whitespaces + start_tag_len <= column as usize
 4482                                    } else {
 4483                                        false
 4484                                    }
 4485                                };
 4486
 4487                                let cursor_is_after_delimiter = {
 4488                                    let delimiter_trim = delimiter.trim_end();
 4489                                    let delimiter_line = snapshot
 4490                                        .chars_for_range(range.clone())
 4491                                        .skip(num_of_whitespaces)
 4492                                        .take(delimiter_trim.len())
 4493                                        .collect::<String>();
 4494                                    if delimiter_line.starts_with(delimiter_trim) {
 4495                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4496                                    } else {
 4497                                        false
 4498                                    }
 4499                                };
 4500
 4501                                let cursor_is_before_end_tag_if_exists = {
 4502                                    let mut char_position = 0u32;
 4503                                    let mut end_tag_offset = None;
 4504
 4505                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4506                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4507                                            let chars_before_match =
 4508                                                chunk[..byte_pos].chars().count() as u32;
 4509                                            end_tag_offset =
 4510                                                Some(char_position + chars_before_match);
 4511                                            break 'outer;
 4512                                        }
 4513                                        char_position += chunk.chars().count() as u32;
 4514                                    }
 4515
 4516                                    if let Some(end_tag_offset) = end_tag_offset {
 4517                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4518                                        if cursor_is_after_start_tag {
 4519                                            if cursor_is_before_end_tag {
 4520                                                insert_extra_newline = true;
 4521                                            }
 4522                                            let cursor_is_at_start_of_end_tag =
 4523                                                column == end_tag_offset;
 4524                                            if cursor_is_at_start_of_end_tag {
 4525                                                indent_on_extra_newline.len = *len;
 4526                                            }
 4527                                        }
 4528                                        cursor_is_before_end_tag
 4529                                    } else {
 4530                                        true
 4531                                    }
 4532                                };
 4533
 4534                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4535                                    && cursor_is_before_end_tag_if_exists
 4536                                {
 4537                                    if cursor_is_after_start_tag {
 4538                                        indent_on_newline.len = *len;
 4539                                    }
 4540                                    Some(delimiter.clone())
 4541                                } else {
 4542                                    None
 4543                                }
 4544                            });
 4545
 4546                            (
 4547                                comment_delimiter,
 4548                                doc_delimiter,
 4549                                insert_extra_newline,
 4550                                indent_on_newline,
 4551                                indent_on_extra_newline,
 4552                            )
 4553                        } else {
 4554                            (
 4555                                None,
 4556                                None,
 4557                                false,
 4558                                IndentSize::default(),
 4559                                IndentSize::default(),
 4560                            )
 4561                        };
 4562
 4563                        let prevent_auto_indent = doc_delimiter.is_some();
 4564                        let delimiter = comment_delimiter.or(doc_delimiter);
 4565
 4566                        let capacity_for_delimiter =
 4567                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4568                        let mut new_text = String::with_capacity(
 4569                            1 + capacity_for_delimiter
 4570                                + existing_indent.len as usize
 4571                                + indent_on_newline.len as usize
 4572                                + indent_on_extra_newline.len as usize,
 4573                        );
 4574                        new_text.push('\n');
 4575                        new_text.extend(existing_indent.chars());
 4576                        new_text.extend(indent_on_newline.chars());
 4577
 4578                        if let Some(delimiter) = &delimiter {
 4579                            new_text.push_str(delimiter);
 4580                        }
 4581
 4582                        if insert_extra_newline {
 4583                            new_text.push('\n');
 4584                            new_text.extend(existing_indent.chars());
 4585                            new_text.extend(indent_on_extra_newline.chars());
 4586                        }
 4587
 4588                        let anchor = buffer.anchor_after(end);
 4589                        let new_selection = selection.map(|_| anchor);
 4590                        (
 4591                            ((start..end, new_text), prevent_auto_indent),
 4592                            (insert_extra_newline, new_selection),
 4593                        )
 4594                    })
 4595                    .unzip()
 4596            };
 4597
 4598            let mut auto_indent_edits = Vec::new();
 4599            let mut edits = Vec::new();
 4600            for (edit, prevent_auto_indent) in edits_with_flags {
 4601                if prevent_auto_indent {
 4602                    edits.push(edit);
 4603                } else {
 4604                    auto_indent_edits.push(edit);
 4605                }
 4606            }
 4607            if !edits.is_empty() {
 4608                this.edit(edits, cx);
 4609            }
 4610            if !auto_indent_edits.is_empty() {
 4611                this.edit_with_autoindent(auto_indent_edits, cx);
 4612            }
 4613
 4614            let buffer = this.buffer.read(cx).snapshot(cx);
 4615            let new_selections = selection_info
 4616                .into_iter()
 4617                .map(|(extra_newline_inserted, new_selection)| {
 4618                    let mut cursor = new_selection.end.to_point(&buffer);
 4619                    if extra_newline_inserted {
 4620                        cursor.row -= 1;
 4621                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4622                    }
 4623                    new_selection.map(|_| cursor)
 4624                })
 4625                .collect();
 4626
 4627            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4628            this.refresh_inline_completion(true, false, window, cx);
 4629        });
 4630    }
 4631
 4632    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4634
 4635        let buffer = self.buffer.read(cx);
 4636        let snapshot = buffer.snapshot(cx);
 4637
 4638        let mut edits = Vec::new();
 4639        let mut rows = Vec::new();
 4640
 4641        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4642            let cursor = selection.head();
 4643            let row = cursor.row;
 4644
 4645            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4646
 4647            let newline = "\n".to_string();
 4648            edits.push((start_of_line..start_of_line, newline));
 4649
 4650            rows.push(row + rows_inserted as u32);
 4651        }
 4652
 4653        self.transact(window, cx, |editor, window, cx| {
 4654            editor.edit(edits, cx);
 4655
 4656            editor.change_selections(Default::default(), window, cx, |s| {
 4657                let mut index = 0;
 4658                s.move_cursors_with(|map, _, _| {
 4659                    let row = rows[index];
 4660                    index += 1;
 4661
 4662                    let point = Point::new(row, 0);
 4663                    let boundary = map.next_line_boundary(point).1;
 4664                    let clipped = map.clip_point(boundary, Bias::Left);
 4665
 4666                    (clipped, SelectionGoal::None)
 4667                });
 4668            });
 4669
 4670            let mut indent_edits = Vec::new();
 4671            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4672            for row in rows {
 4673                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4674                for (row, indent) in indents {
 4675                    if indent.len == 0 {
 4676                        continue;
 4677                    }
 4678
 4679                    let text = match indent.kind {
 4680                        IndentKind::Space => " ".repeat(indent.len as usize),
 4681                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4682                    };
 4683                    let point = Point::new(row.0, 0);
 4684                    indent_edits.push((point..point, text));
 4685                }
 4686            }
 4687            editor.edit(indent_edits, cx);
 4688        });
 4689    }
 4690
 4691    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4693
 4694        let buffer = self.buffer.read(cx);
 4695        let snapshot = buffer.snapshot(cx);
 4696
 4697        let mut edits = Vec::new();
 4698        let mut rows = Vec::new();
 4699        let mut rows_inserted = 0;
 4700
 4701        for selection in self.selections.all_adjusted(cx) {
 4702            let cursor = selection.head();
 4703            let row = cursor.row;
 4704
 4705            let point = Point::new(row + 1, 0);
 4706            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4707
 4708            let newline = "\n".to_string();
 4709            edits.push((start_of_line..start_of_line, newline));
 4710
 4711            rows_inserted += 1;
 4712            rows.push(row + rows_inserted);
 4713        }
 4714
 4715        self.transact(window, cx, |editor, window, cx| {
 4716            editor.edit(edits, cx);
 4717
 4718            editor.change_selections(Default::default(), window, cx, |s| {
 4719                let mut index = 0;
 4720                s.move_cursors_with(|map, _, _| {
 4721                    let row = rows[index];
 4722                    index += 1;
 4723
 4724                    let point = Point::new(row, 0);
 4725                    let boundary = map.next_line_boundary(point).1;
 4726                    let clipped = map.clip_point(boundary, Bias::Left);
 4727
 4728                    (clipped, SelectionGoal::None)
 4729                });
 4730            });
 4731
 4732            let mut indent_edits = Vec::new();
 4733            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4734            for row in rows {
 4735                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4736                for (row, indent) in indents {
 4737                    if indent.len == 0 {
 4738                        continue;
 4739                    }
 4740
 4741                    let text = match indent.kind {
 4742                        IndentKind::Space => " ".repeat(indent.len as usize),
 4743                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4744                    };
 4745                    let point = Point::new(row.0, 0);
 4746                    indent_edits.push((point..point, text));
 4747                }
 4748            }
 4749            editor.edit(indent_edits, cx);
 4750        });
 4751    }
 4752
 4753    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4754        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4755            original_indent_columns: Vec::new(),
 4756        });
 4757        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4758    }
 4759
 4760    fn insert_with_autoindent_mode(
 4761        &mut self,
 4762        text: &str,
 4763        autoindent_mode: Option<AutoindentMode>,
 4764        window: &mut Window,
 4765        cx: &mut Context<Self>,
 4766    ) {
 4767        if self.read_only(cx) {
 4768            return;
 4769        }
 4770
 4771        let text: Arc<str> = text.into();
 4772        self.transact(window, cx, |this, window, cx| {
 4773            let old_selections = this.selections.all_adjusted(cx);
 4774            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4775                let anchors = {
 4776                    let snapshot = buffer.read(cx);
 4777                    old_selections
 4778                        .iter()
 4779                        .map(|s| {
 4780                            let anchor = snapshot.anchor_after(s.head());
 4781                            s.map(|_| anchor)
 4782                        })
 4783                        .collect::<Vec<_>>()
 4784                };
 4785                buffer.edit(
 4786                    old_selections
 4787                        .iter()
 4788                        .map(|s| (s.start..s.end, text.clone())),
 4789                    autoindent_mode,
 4790                    cx,
 4791                );
 4792                anchors
 4793            });
 4794
 4795            this.change_selections(Default::default(), window, cx, |s| {
 4796                s.select_anchors(selection_anchors);
 4797            });
 4798
 4799            cx.notify();
 4800        });
 4801    }
 4802
 4803    fn trigger_completion_on_input(
 4804        &mut self,
 4805        text: &str,
 4806        trigger_in_words: bool,
 4807        window: &mut Window,
 4808        cx: &mut Context<Self>,
 4809    ) {
 4810        let completions_source = self
 4811            .context_menu
 4812            .borrow()
 4813            .as_ref()
 4814            .and_then(|menu| match menu {
 4815                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4816                CodeContextMenu::CodeActions(_) => None,
 4817            });
 4818
 4819        match completions_source {
 4820            Some(CompletionsMenuSource::Words) => {
 4821                self.show_word_completions(&ShowWordCompletions, window, cx)
 4822            }
 4823            Some(CompletionsMenuSource::Normal)
 4824            | Some(CompletionsMenuSource::SnippetChoices)
 4825            | None
 4826                if self.is_completion_trigger(
 4827                    text,
 4828                    trigger_in_words,
 4829                    completions_source.is_some(),
 4830                    cx,
 4831                ) =>
 4832            {
 4833                self.show_completions(
 4834                    &ShowCompletions {
 4835                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4836                    },
 4837                    window,
 4838                    cx,
 4839                )
 4840            }
 4841            _ => {
 4842                self.hide_context_menu(window, cx);
 4843            }
 4844        }
 4845    }
 4846
 4847    fn is_completion_trigger(
 4848        &self,
 4849        text: &str,
 4850        trigger_in_words: bool,
 4851        menu_is_open: bool,
 4852        cx: &mut Context<Self>,
 4853    ) -> bool {
 4854        let position = self.selections.newest_anchor().head();
 4855        let multibuffer = self.buffer.read(cx);
 4856        let Some(buffer) = position
 4857            .buffer_id
 4858            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4859        else {
 4860            return false;
 4861        };
 4862
 4863        if let Some(completion_provider) = &self.completion_provider {
 4864            completion_provider.is_completion_trigger(
 4865                &buffer,
 4866                position.text_anchor,
 4867                text,
 4868                trigger_in_words,
 4869                menu_is_open,
 4870                cx,
 4871            )
 4872        } else {
 4873            false
 4874        }
 4875    }
 4876
 4877    /// If any empty selections is touching the start of its innermost containing autoclose
 4878    /// region, expand it to select the brackets.
 4879    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4880        let selections = self.selections.all::<usize>(cx);
 4881        let buffer = self.buffer.read(cx).read(cx);
 4882        let new_selections = self
 4883            .selections_with_autoclose_regions(selections, &buffer)
 4884            .map(|(mut selection, region)| {
 4885                if !selection.is_empty() {
 4886                    return selection;
 4887                }
 4888
 4889                if let Some(region) = region {
 4890                    let mut range = region.range.to_offset(&buffer);
 4891                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4892                        range.start -= region.pair.start.len();
 4893                        if buffer.contains_str_at(range.start, &region.pair.start)
 4894                            && buffer.contains_str_at(range.end, &region.pair.end)
 4895                        {
 4896                            range.end += region.pair.end.len();
 4897                            selection.start = range.start;
 4898                            selection.end = range.end;
 4899
 4900                            return selection;
 4901                        }
 4902                    }
 4903                }
 4904
 4905                let always_treat_brackets_as_autoclosed = buffer
 4906                    .language_settings_at(selection.start, cx)
 4907                    .always_treat_brackets_as_autoclosed;
 4908
 4909                if !always_treat_brackets_as_autoclosed {
 4910                    return selection;
 4911                }
 4912
 4913                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4914                    for (pair, enabled) in scope.brackets() {
 4915                        if !enabled || !pair.close {
 4916                            continue;
 4917                        }
 4918
 4919                        if buffer.contains_str_at(selection.start, &pair.end) {
 4920                            let pair_start_len = pair.start.len();
 4921                            if buffer.contains_str_at(
 4922                                selection.start.saturating_sub(pair_start_len),
 4923                                &pair.start,
 4924                            ) {
 4925                                selection.start -= pair_start_len;
 4926                                selection.end += pair.end.len();
 4927
 4928                                return selection;
 4929                            }
 4930                        }
 4931                    }
 4932                }
 4933
 4934                selection
 4935            })
 4936            .collect();
 4937
 4938        drop(buffer);
 4939        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4940            selections.select(new_selections)
 4941        });
 4942    }
 4943
 4944    /// Iterate the given selections, and for each one, find the smallest surrounding
 4945    /// autoclose region. This uses the ordering of the selections and the autoclose
 4946    /// regions to avoid repeated comparisons.
 4947    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4948        &'a self,
 4949        selections: impl IntoIterator<Item = Selection<D>>,
 4950        buffer: &'a MultiBufferSnapshot,
 4951    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4952        let mut i = 0;
 4953        let mut regions = self.autoclose_regions.as_slice();
 4954        selections.into_iter().map(move |selection| {
 4955            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4956
 4957            let mut enclosing = None;
 4958            while let Some(pair_state) = regions.get(i) {
 4959                if pair_state.range.end.to_offset(buffer) < range.start {
 4960                    regions = &regions[i + 1..];
 4961                    i = 0;
 4962                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4963                    break;
 4964                } else {
 4965                    if pair_state.selection_id == selection.id {
 4966                        enclosing = Some(pair_state);
 4967                    }
 4968                    i += 1;
 4969                }
 4970            }
 4971
 4972            (selection, enclosing)
 4973        })
 4974    }
 4975
 4976    /// Remove any autoclose regions that no longer contain their selection.
 4977    fn invalidate_autoclose_regions(
 4978        &mut self,
 4979        mut selections: &[Selection<Anchor>],
 4980        buffer: &MultiBufferSnapshot,
 4981    ) {
 4982        self.autoclose_regions.retain(|state| {
 4983            let mut i = 0;
 4984            while let Some(selection) = selections.get(i) {
 4985                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4986                    selections = &selections[1..];
 4987                    continue;
 4988                }
 4989                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4990                    break;
 4991                }
 4992                if selection.id == state.selection_id {
 4993                    return true;
 4994                } else {
 4995                    i += 1;
 4996                }
 4997            }
 4998            false
 4999        });
 5000    }
 5001
 5002    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5003        let offset = position.to_offset(buffer);
 5004        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5005        if offset > word_range.start && kind == Some(CharKind::Word) {
 5006            Some(
 5007                buffer
 5008                    .text_for_range(word_range.start..offset)
 5009                    .collect::<String>(),
 5010            )
 5011        } else {
 5012            None
 5013        }
 5014    }
 5015
 5016    pub fn toggle_inline_values(
 5017        &mut self,
 5018        _: &ToggleInlineValues,
 5019        _: &mut Window,
 5020        cx: &mut Context<Self>,
 5021    ) {
 5022        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5023
 5024        self.refresh_inline_values(cx);
 5025    }
 5026
 5027    pub fn toggle_inlay_hints(
 5028        &mut self,
 5029        _: &ToggleInlayHints,
 5030        _: &mut Window,
 5031        cx: &mut Context<Self>,
 5032    ) {
 5033        self.refresh_inlay_hints(
 5034            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5035            cx,
 5036        );
 5037    }
 5038
 5039    pub fn inlay_hints_enabled(&self) -> bool {
 5040        self.inlay_hint_cache.enabled
 5041    }
 5042
 5043    pub fn inline_values_enabled(&self) -> bool {
 5044        self.inline_value_cache.enabled
 5045    }
 5046
 5047    #[cfg(any(test, feature = "test-support"))]
 5048    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5049        self.display_map
 5050            .read(cx)
 5051            .current_inlays()
 5052            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    #[cfg(any(test, feature = "test-support"))]
 5058    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5059        self.display_map
 5060            .read(cx)
 5061            .current_inlays()
 5062            .cloned()
 5063            .collect()
 5064    }
 5065
 5066    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5067        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5068            return;
 5069        }
 5070
 5071        let reason_description = reason.description();
 5072        let ignore_debounce = matches!(
 5073            reason,
 5074            InlayHintRefreshReason::SettingsChange(_)
 5075                | InlayHintRefreshReason::Toggle(_)
 5076                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5077                | InlayHintRefreshReason::ModifiersChanged(_)
 5078        );
 5079        let (invalidate_cache, required_languages) = match reason {
 5080            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5081                match self.inlay_hint_cache.modifiers_override(enabled) {
 5082                    Some(enabled) => {
 5083                        if enabled {
 5084                            (InvalidationStrategy::RefreshRequested, None)
 5085                        } else {
 5086                            self.splice_inlays(
 5087                                &self
 5088                                    .visible_inlay_hints(cx)
 5089                                    .iter()
 5090                                    .map(|inlay| inlay.id)
 5091                                    .collect::<Vec<InlayId>>(),
 5092                                Vec::new(),
 5093                                cx,
 5094                            );
 5095                            return;
 5096                        }
 5097                    }
 5098                    None => return,
 5099                }
 5100            }
 5101            InlayHintRefreshReason::Toggle(enabled) => {
 5102                if self.inlay_hint_cache.toggle(enabled) {
 5103                    if enabled {
 5104                        (InvalidationStrategy::RefreshRequested, None)
 5105                    } else {
 5106                        self.splice_inlays(
 5107                            &self
 5108                                .visible_inlay_hints(cx)
 5109                                .iter()
 5110                                .map(|inlay| inlay.id)
 5111                                .collect::<Vec<InlayId>>(),
 5112                            Vec::new(),
 5113                            cx,
 5114                        );
 5115                        return;
 5116                    }
 5117                } else {
 5118                    return;
 5119                }
 5120            }
 5121            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5122                match self.inlay_hint_cache.update_settings(
 5123                    &self.buffer,
 5124                    new_settings,
 5125                    self.visible_inlay_hints(cx),
 5126                    cx,
 5127                ) {
 5128                    ControlFlow::Break(Some(InlaySplice {
 5129                        to_remove,
 5130                        to_insert,
 5131                    })) => {
 5132                        self.splice_inlays(&to_remove, to_insert, cx);
 5133                        return;
 5134                    }
 5135                    ControlFlow::Break(None) => return,
 5136                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5137                }
 5138            }
 5139            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5140                if let Some(InlaySplice {
 5141                    to_remove,
 5142                    to_insert,
 5143                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5144                {
 5145                    self.splice_inlays(&to_remove, to_insert, cx);
 5146                }
 5147                self.display_map.update(cx, |display_map, _| {
 5148                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5149                });
 5150                return;
 5151            }
 5152            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5153            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5154                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5155            }
 5156            InlayHintRefreshReason::RefreshRequested => {
 5157                (InvalidationStrategy::RefreshRequested, None)
 5158            }
 5159        };
 5160
 5161        if let Some(InlaySplice {
 5162            to_remove,
 5163            to_insert,
 5164        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5165            reason_description,
 5166            self.visible_excerpts(required_languages.as_ref(), cx),
 5167            invalidate_cache,
 5168            ignore_debounce,
 5169            cx,
 5170        ) {
 5171            self.splice_inlays(&to_remove, to_insert, cx);
 5172        }
 5173    }
 5174
 5175    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5180            .cloned()
 5181            .collect()
 5182    }
 5183
 5184    pub fn visible_excerpts(
 5185        &self,
 5186        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project.as_ref() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5206        multi_buffer_snapshot
 5207            .range_to_buffer_ranges(multi_buffer_visible_range)
 5208            .into_iter()
 5209            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5210            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5211                let buffer_file = project::File::from_dyn(buffer.file())?;
 5212                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5213                let worktree_entry = buffer_worktree
 5214                    .read(cx)
 5215                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5216                if worktree_entry.is_ignored {
 5217                    return None;
 5218                }
 5219
 5220                let language = buffer.language()?;
 5221                if let Some(restrict_to_languages) = restrict_to_languages {
 5222                    if !restrict_to_languages.contains(language) {
 5223                        return None;
 5224                    }
 5225                }
 5226                Some((
 5227                    excerpt_id,
 5228                    (
 5229                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5230                        buffer.version().clone(),
 5231                        excerpt_visible_range,
 5232                    ),
 5233                ))
 5234            })
 5235            .collect()
 5236    }
 5237
 5238    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5239        TextLayoutDetails {
 5240            text_system: window.text_system().clone(),
 5241            editor_style: self.style.clone().unwrap(),
 5242            rem_size: window.rem_size(),
 5243            scroll_anchor: self.scroll_manager.anchor(),
 5244            visible_rows: self.visible_line_count(),
 5245            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5246        }
 5247    }
 5248
 5249    pub fn splice_inlays(
 5250        &self,
 5251        to_remove: &[InlayId],
 5252        to_insert: Vec<Inlay>,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        self.display_map.update(cx, |display_map, cx| {
 5256            display_map.splice_inlays(to_remove, to_insert, cx)
 5257        });
 5258        cx.notify();
 5259    }
 5260
 5261    fn trigger_on_type_formatting(
 5262        &self,
 5263        input: String,
 5264        window: &mut Window,
 5265        cx: &mut Context<Self>,
 5266    ) -> Option<Task<Result<()>>> {
 5267        if input.len() != 1 {
 5268            return None;
 5269        }
 5270
 5271        let project = self.project.as_ref()?;
 5272        let position = self.selections.newest_anchor().head();
 5273        let (buffer, buffer_position) = self
 5274            .buffer
 5275            .read(cx)
 5276            .text_anchor_for_position(position, cx)?;
 5277
 5278        let settings = language_settings::language_settings(
 5279            buffer
 5280                .read(cx)
 5281                .language_at(buffer_position)
 5282                .map(|l| l.name()),
 5283            buffer.read(cx).file(),
 5284            cx,
 5285        );
 5286        if !settings.use_on_type_format {
 5287            return None;
 5288        }
 5289
 5290        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5291        // hence we do LSP request & edit on host side only — add formats to host's history.
 5292        let push_to_lsp_host_history = true;
 5293        // If this is not the host, append its history with new edits.
 5294        let push_to_client_history = project.read(cx).is_via_collab();
 5295
 5296        let on_type_formatting = project.update(cx, |project, cx| {
 5297            project.on_type_format(
 5298                buffer.clone(),
 5299                buffer_position,
 5300                input,
 5301                push_to_lsp_host_history,
 5302                cx,
 5303            )
 5304        });
 5305        Some(cx.spawn_in(window, async move |editor, cx| {
 5306            if let Some(transaction) = on_type_formatting.await? {
 5307                if push_to_client_history {
 5308                    buffer
 5309                        .update(cx, |buffer, _| {
 5310                            buffer.push_transaction(transaction, Instant::now());
 5311                            buffer.finalize_last_transaction();
 5312                        })
 5313                        .ok();
 5314                }
 5315                editor.update(cx, |editor, cx| {
 5316                    editor.refresh_document_highlights(cx);
 5317                })?;
 5318            }
 5319            Ok(())
 5320        }))
 5321    }
 5322
 5323    pub fn show_word_completions(
 5324        &mut self,
 5325        _: &ShowWordCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5330    }
 5331
 5332    pub fn show_completions(
 5333        &mut self,
 5334        options: &ShowCompletions,
 5335        window: &mut Window,
 5336        cx: &mut Context<Self>,
 5337    ) {
 5338        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5339    }
 5340
 5341    fn open_or_update_completions_menu(
 5342        &mut self,
 5343        requested_source: Option<CompletionsMenuSource>,
 5344        trigger: Option<&str>,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        if self.pending_rename.is_some() {
 5349            return;
 5350        }
 5351
 5352        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5353
 5354        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5355        // inserted and selected. To handle that case, the start of the selection is used so that
 5356        // the menu starts with all choices.
 5357        let position = self
 5358            .selections
 5359            .newest_anchor()
 5360            .start
 5361            .bias_right(&multibuffer_snapshot);
 5362        if position.diff_base_anchor.is_some() {
 5363            return;
 5364        }
 5365        let (buffer, buffer_position) =
 5366            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5367                output
 5368            } else {
 5369                return;
 5370            };
 5371        let buffer_snapshot = buffer.read(cx).snapshot();
 5372
 5373        let query: Option<Arc<String>> =
 5374            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5375
 5376        drop(multibuffer_snapshot);
 5377
 5378        let provider = match requested_source {
 5379            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5380            Some(CompletionsMenuSource::Words) => None,
 5381            Some(CompletionsMenuSource::SnippetChoices) => {
 5382                log::error!("bug: SnippetChoices requested_source is not handled");
 5383                None
 5384            }
 5385        };
 5386
 5387        let sort_completions = provider
 5388            .as_ref()
 5389            .map_or(false, |provider| provider.sort_completions());
 5390
 5391        let filter_completions = provider
 5392            .as_ref()
 5393            .map_or(true, |provider| provider.filter_completions());
 5394
 5395        let trigger_kind = match trigger {
 5396            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5397                CompletionTriggerKind::TRIGGER_CHARACTER
 5398            }
 5399            _ => CompletionTriggerKind::INVOKED,
 5400        };
 5401        let completion_context = CompletionContext {
 5402            trigger_character: trigger.and_then(|trigger| {
 5403                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5404                    Some(String::from(trigger))
 5405                } else {
 5406                    None
 5407                }
 5408            }),
 5409            trigger_kind,
 5410        };
 5411
 5412        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5413        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5414        // involve trigger chars, so this is skipped in that case.
 5415        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5416        {
 5417            let menu_is_open = matches!(
 5418                self.context_menu.borrow().as_ref(),
 5419                Some(CodeContextMenu::Completions(_))
 5420            );
 5421            if menu_is_open {
 5422                self.hide_context_menu(window, cx);
 5423            }
 5424        }
 5425
 5426        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5427            if filter_completions {
 5428                menu.filter(query.clone(), provider.clone(), window, cx);
 5429            }
 5430            // When `is_incomplete` is false, no need to re-query completions when the current query
 5431            // is a suffix of the initial query.
 5432            if !menu.is_incomplete {
 5433                // If the new query is a suffix of the old query (typing more characters) and
 5434                // the previous result was complete, the existing completions can be filtered.
 5435                //
 5436                // Note that this is always true for snippet completions.
 5437                let query_matches = match (&menu.initial_query, &query) {
 5438                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5439                    (None, _) => true,
 5440                    _ => false,
 5441                };
 5442                if query_matches {
 5443                    let position_matches = if menu.initial_position == position {
 5444                        true
 5445                    } else {
 5446                        let snapshot = self.buffer.read(cx).read(cx);
 5447                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5448                    };
 5449                    if position_matches {
 5450                        return;
 5451                    }
 5452                }
 5453            }
 5454        };
 5455
 5456        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5457            buffer_snapshot.surrounding_word(buffer_position, false)
 5458        {
 5459            let word_to_exclude = buffer_snapshot
 5460                .text_for_range(word_range.clone())
 5461                .collect::<String>();
 5462            (
 5463                buffer_snapshot.anchor_before(word_range.start)
 5464                    ..buffer_snapshot.anchor_after(buffer_position),
 5465                Some(word_to_exclude),
 5466            )
 5467        } else {
 5468            (buffer_position..buffer_position, None)
 5469        };
 5470
 5471        let language = buffer_snapshot
 5472            .language_at(buffer_position)
 5473            .map(|language| language.name());
 5474
 5475        let completion_settings =
 5476            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5477
 5478        let show_completion_documentation = buffer_snapshot
 5479            .settings_at(buffer_position, cx)
 5480            .show_completion_documentation;
 5481
 5482        // The document can be large, so stay in reasonable bounds when searching for words,
 5483        // otherwise completion pop-up might be slow to appear.
 5484        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5485        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5486        let min_word_search = buffer_snapshot.clip_point(
 5487            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5488            Bias::Left,
 5489        );
 5490        let max_word_search = buffer_snapshot.clip_point(
 5491            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5492            Bias::Right,
 5493        );
 5494        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5495            ..buffer_snapshot.point_to_offset(max_word_search);
 5496
 5497        let skip_digits = query
 5498            .as_ref()
 5499            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5500
 5501        let (mut words, provider_responses) = match &provider {
 5502            Some(provider) => {
 5503                let provider_responses = provider.completions(
 5504                    position.excerpt_id,
 5505                    &buffer,
 5506                    buffer_position,
 5507                    completion_context,
 5508                    window,
 5509                    cx,
 5510                );
 5511
 5512                let words = match completion_settings.words {
 5513                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5514                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5515                        .background_spawn(async move {
 5516                            buffer_snapshot.words_in_range(WordsQuery {
 5517                                fuzzy_contents: None,
 5518                                range: word_search_range,
 5519                                skip_digits,
 5520                            })
 5521                        }),
 5522                };
 5523
 5524                (words, provider_responses)
 5525            }
 5526            None => (
 5527                cx.background_spawn(async move {
 5528                    buffer_snapshot.words_in_range(WordsQuery {
 5529                        fuzzy_contents: None,
 5530                        range: word_search_range,
 5531                        skip_digits,
 5532                    })
 5533                }),
 5534                Task::ready(Ok(Vec::new())),
 5535            ),
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            if let Some(provider_responses) = provider_responses.await.log_err() {
 5553                if !provider_responses.is_empty() {
 5554                    for response in provider_responses {
 5555                        completions.extend(response.completions);
 5556                        is_incomplete = is_incomplete || response.is_incomplete;
 5557                    }
 5558                    if completion_settings.words == WordsCompletionMode::Fallback {
 5559                        words = Task::ready(BTreeMap::default());
 5560                    }
 5561                }
 5562            }
 5563
 5564            let mut words = words.await;
 5565            if let Some(word_to_exclude) = &word_to_exclude {
 5566                words.remove(word_to_exclude);
 5567            }
 5568            for lsp_completion in &completions {
 5569                words.remove(&lsp_completion.new_text);
 5570            }
 5571            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5572                replace_range: word_replace_range.clone(),
 5573                new_text: word.clone(),
 5574                label: CodeLabel::plain(word, None),
 5575                icon_path: None,
 5576                documentation: None,
 5577                source: CompletionSource::BufferWord {
 5578                    word_range,
 5579                    resolved: false,
 5580                },
 5581                insert_text_mode: Some(InsertTextMode::AS_IS),
 5582                confirm: None,
 5583            }));
 5584
 5585            let menu = if completions.is_empty() {
 5586                None
 5587            } else {
 5588                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5589                    let languages = editor
 5590                        .workspace
 5591                        .as_ref()
 5592                        .and_then(|(workspace, _)| workspace.upgrade())
 5593                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5594                    let menu = CompletionsMenu::new(
 5595                        id,
 5596                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5597                        sort_completions,
 5598                        show_completion_documentation,
 5599                        position,
 5600                        query.clone(),
 5601                        is_incomplete,
 5602                        buffer.clone(),
 5603                        completions.into(),
 5604                        snippet_sort_order,
 5605                        languages,
 5606                        language,
 5607                        cx,
 5608                    );
 5609
 5610                    let query = if filter_completions { query } else { None };
 5611                    let matches_task = if let Some(query) = query {
 5612                        menu.do_async_filtering(query, cx)
 5613                    } else {
 5614                        Task::ready(menu.unfiltered_matches())
 5615                    };
 5616                    (menu, matches_task)
 5617                }) else {
 5618                    return;
 5619                };
 5620
 5621                let matches = matches_task.await;
 5622
 5623                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5624                    // Newer menu already set, so exit.
 5625                    match editor.context_menu.borrow().as_ref() {
 5626                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5627                            if prev_menu.id > id {
 5628                                return;
 5629                            }
 5630                        }
 5631                        _ => {}
 5632                    };
 5633
 5634                    // Only valid to take prev_menu because it the new menu is immediately set
 5635                    // below, or the menu is hidden.
 5636                    match editor.context_menu.borrow_mut().take() {
 5637                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5638                            let position_matches =
 5639                                if prev_menu.initial_position == menu.initial_position {
 5640                                    true
 5641                                } else {
 5642                                    let snapshot = editor.buffer.read(cx).read(cx);
 5643                                    prev_menu.initial_position.to_offset(&snapshot)
 5644                                        == menu.initial_position.to_offset(&snapshot)
 5645                                };
 5646                            if position_matches {
 5647                                // Preserve markdown cache before `set_filter_results` because it will
 5648                                // try to populate the documentation cache.
 5649                                menu.preserve_markdown_cache(prev_menu);
 5650                            }
 5651                        }
 5652                        _ => {}
 5653                    };
 5654
 5655                    menu.set_filter_results(matches, provider, window, cx);
 5656                }) else {
 5657                    return;
 5658                };
 5659
 5660                menu.visible().then_some(menu)
 5661            };
 5662
 5663            editor
 5664                .update_in(cx, |editor, window, cx| {
 5665                    if editor.focus_handle.is_focused(window) {
 5666                        if let Some(menu) = menu {
 5667                            *editor.context_menu.borrow_mut() =
 5668                                Some(CodeContextMenu::Completions(menu));
 5669
 5670                            crate::hover_popover::hide_hover(editor, cx);
 5671                            if editor.show_edit_predictions_in_menu() {
 5672                                editor.update_visible_inline_completion(window, cx);
 5673                            } else {
 5674                                editor.discard_inline_completion(false, cx);
 5675                            }
 5676
 5677                            cx.notify();
 5678                            return;
 5679                        }
 5680                    }
 5681
 5682                    if editor.completion_tasks.len() <= 1 {
 5683                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5684                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5685                        // If it was already hidden and we don't show inline completions in the menu, we should
 5686                        // also show the inline-completion when available.
 5687                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5688                            editor.update_visible_inline_completion(window, cx);
 5689                        }
 5690                    }
 5691                })
 5692                .ok();
 5693        });
 5694
 5695        self.completion_tasks.push((id, task));
 5696    }
 5697
 5698    #[cfg(feature = "test-support")]
 5699    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5700        let menu = self.context_menu.borrow();
 5701        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5702            let completions = menu.completions.borrow();
 5703            Some(completions.to_vec())
 5704        } else {
 5705            None
 5706        }
 5707    }
 5708
 5709    pub fn with_completions_menu_matching_id<R>(
 5710        &self,
 5711        id: CompletionId,
 5712        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5713    ) -> R {
 5714        let mut context_menu = self.context_menu.borrow_mut();
 5715        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5716            return f(None);
 5717        };
 5718        if completions_menu.id != id {
 5719            return f(None);
 5720        }
 5721        f(Some(completions_menu))
 5722    }
 5723
 5724    pub fn confirm_completion(
 5725        &mut self,
 5726        action: &ConfirmCompletion,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5732    }
 5733
 5734    pub fn confirm_completion_insert(
 5735        &mut self,
 5736        _: &ConfirmCompletionInsert,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5742    }
 5743
 5744    pub fn confirm_completion_replace(
 5745        &mut self,
 5746        _: &ConfirmCompletionReplace,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) -> Option<Task<Result<()>>> {
 5750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5751        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5752    }
 5753
 5754    pub fn compose_completion(
 5755        &mut self,
 5756        action: &ComposeCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5762    }
 5763
 5764    fn do_completion(
 5765        &mut self,
 5766        item_ix: Option<usize>,
 5767        intent: CompletionIntent,
 5768        window: &mut Window,
 5769        cx: &mut Context<Editor>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        use language::ToOffset as _;
 5772
 5773        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5774        else {
 5775            return None;
 5776        };
 5777
 5778        let candidate_id = {
 5779            let entries = completions_menu.entries.borrow();
 5780            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5781            if self.show_edit_predictions_in_menu() {
 5782                self.discard_inline_completion(true, cx);
 5783            }
 5784            mat.candidate_id
 5785        };
 5786
 5787        let completion = completions_menu
 5788            .completions
 5789            .borrow()
 5790            .get(candidate_id)?
 5791            .clone();
 5792        cx.stop_propagation();
 5793
 5794        let buffer_handle = completions_menu.buffer.clone();
 5795
 5796        let CompletionEdit {
 5797            new_text,
 5798            snippet,
 5799            replace_range,
 5800        } = process_completion_for_edit(
 5801            &completion,
 5802            intent,
 5803            &buffer_handle,
 5804            &completions_menu.initial_position.text_anchor,
 5805            cx,
 5806        );
 5807
 5808        let buffer = buffer_handle.read(cx);
 5809        let snapshot = self.buffer.read(cx).snapshot(cx);
 5810        let newest_anchor = self.selections.newest_anchor();
 5811        let replace_range_multibuffer = {
 5812            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5813            let multibuffer_anchor = snapshot
 5814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5815                .unwrap()
 5816                ..snapshot
 5817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5818                    .unwrap();
 5819            multibuffer_anchor.start.to_offset(&snapshot)
 5820                ..multibuffer_anchor.end.to_offset(&snapshot)
 5821        };
 5822        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5823            return None;
 5824        }
 5825
 5826        let old_text = buffer
 5827            .text_for_range(replace_range.clone())
 5828            .collect::<String>();
 5829        let lookbehind = newest_anchor
 5830            .start
 5831            .text_anchor
 5832            .to_offset(buffer)
 5833            .saturating_sub(replace_range.start);
 5834        let lookahead = replace_range
 5835            .end
 5836            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5837        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5838        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5839
 5840        let selections = self.selections.all::<usize>(cx);
 5841        let mut ranges = Vec::new();
 5842        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5843
 5844        for selection in &selections {
 5845            let range = if selection.id == newest_anchor.id {
 5846                replace_range_multibuffer.clone()
 5847            } else {
 5848                let mut range = selection.range();
 5849
 5850                // if prefix is present, don't duplicate it
 5851                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5852                    range.start = range.start.saturating_sub(lookbehind);
 5853
 5854                    // if suffix is also present, mimic the newest cursor and replace it
 5855                    if selection.id != newest_anchor.id
 5856                        && snapshot.contains_str_at(range.end, suffix)
 5857                    {
 5858                        range.end += lookahead;
 5859                    }
 5860                }
 5861                range
 5862            };
 5863
 5864            ranges.push(range.clone());
 5865
 5866            if !self.linked_edit_ranges.is_empty() {
 5867                let start_anchor = snapshot.anchor_before(range.start);
 5868                let end_anchor = snapshot.anchor_after(range.end);
 5869                if let Some(ranges) = self
 5870                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5871                {
 5872                    for (buffer, edits) in ranges {
 5873                        linked_edits
 5874                            .entry(buffer.clone())
 5875                            .or_default()
 5876                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5877                    }
 5878                }
 5879            }
 5880        }
 5881
 5882        let common_prefix_len = old_text
 5883            .chars()
 5884            .zip(new_text.chars())
 5885            .take_while(|(a, b)| a == b)
 5886            .map(|(a, _)| a.len_utf8())
 5887            .sum::<usize>();
 5888
 5889        cx.emit(EditorEvent::InputHandled {
 5890            utf16_range_to_replace: None,
 5891            text: new_text[common_prefix_len..].into(),
 5892        });
 5893
 5894        self.transact(window, cx, |this, window, cx| {
 5895            if let Some(mut snippet) = snippet {
 5896                snippet.text = new_text.to_string();
 5897                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5898            } else {
 5899                this.buffer.update(cx, |buffer, cx| {
 5900                    let auto_indent = match completion.insert_text_mode {
 5901                        Some(InsertTextMode::AS_IS) => None,
 5902                        _ => this.autoindent_mode.clone(),
 5903                    };
 5904                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5905                    buffer.edit(edits, auto_indent, cx);
 5906                });
 5907            }
 5908            for (buffer, edits) in linked_edits {
 5909                buffer.update(cx, |buffer, cx| {
 5910                    let snapshot = buffer.snapshot();
 5911                    let edits = edits
 5912                        .into_iter()
 5913                        .map(|(range, text)| {
 5914                            use text::ToPoint as TP;
 5915                            let end_point = TP::to_point(&range.end, &snapshot);
 5916                            let start_point = TP::to_point(&range.start, &snapshot);
 5917                            (start_point..end_point, text)
 5918                        })
 5919                        .sorted_by_key(|(range, _)| range.start);
 5920                    buffer.edit(edits, None, cx);
 5921                })
 5922            }
 5923
 5924            this.refresh_inline_completion(true, false, window, cx);
 5925        });
 5926
 5927        let show_new_completions_on_confirm = completion
 5928            .confirm
 5929            .as_ref()
 5930            .map_or(false, |confirm| confirm(intent, window, cx));
 5931        if show_new_completions_on_confirm {
 5932            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5933        }
 5934
 5935        let provider = self.completion_provider.as_ref()?;
 5936        drop(completion);
 5937        let apply_edits = provider.apply_additional_edits_for_completion(
 5938            buffer_handle,
 5939            completions_menu.completions.clone(),
 5940            candidate_id,
 5941            true,
 5942            cx,
 5943        );
 5944
 5945        let editor_settings = EditorSettings::get_global(cx);
 5946        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5947            // After the code completion is finished, users often want to know what signatures are needed.
 5948            // so we should automatically call signature_help
 5949            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5950        }
 5951
 5952        Some(cx.foreground_executor().spawn(async move {
 5953            apply_edits.await?;
 5954            Ok(())
 5955        }))
 5956    }
 5957
 5958    pub fn toggle_code_actions(
 5959        &mut self,
 5960        action: &ToggleCodeActions,
 5961        window: &mut Window,
 5962        cx: &mut Context<Self>,
 5963    ) {
 5964        let quick_launch = action.quick_launch;
 5965        let mut context_menu = self.context_menu.borrow_mut();
 5966        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5967            if code_actions.deployed_from == action.deployed_from {
 5968                // Toggle if we're selecting the same one
 5969                *context_menu = None;
 5970                cx.notify();
 5971                return;
 5972            } else {
 5973                // Otherwise, clear it and start a new one
 5974                *context_menu = None;
 5975                cx.notify();
 5976            }
 5977        }
 5978        drop(context_menu);
 5979        let snapshot = self.snapshot(window, cx);
 5980        let deployed_from = action.deployed_from.clone();
 5981        let action = action.clone();
 5982        self.completion_tasks.clear();
 5983        self.discard_inline_completion(false, cx);
 5984
 5985        let multibuffer_point = match &action.deployed_from {
 5986            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5987                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5988            }
 5989            _ => self.selections.newest::<Point>(cx).head(),
 5990        };
 5991        let Some((buffer, buffer_row)) = snapshot
 5992            .buffer_snapshot
 5993            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5994            .and_then(|(buffer_snapshot, range)| {
 5995                self.buffer()
 5996                    .read(cx)
 5997                    .buffer(buffer_snapshot.remote_id())
 5998                    .map(|buffer| (buffer, range.start.row))
 5999            })
 6000        else {
 6001            return;
 6002        };
 6003        let buffer_id = buffer.read(cx).remote_id();
 6004        let tasks = self
 6005            .tasks
 6006            .get(&(buffer_id, buffer_row))
 6007            .map(|t| Arc::new(t.to_owned()));
 6008
 6009        if !self.focus_handle.is_focused(window) {
 6010            return;
 6011        }
 6012        let project = self.project.clone();
 6013
 6014        let code_actions_task = match deployed_from {
 6015            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6016            _ => self.code_actions(buffer_row, window, cx),
 6017        };
 6018
 6019        let runnable_task = match deployed_from {
 6020            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6021            _ => {
 6022                let mut task_context_task = Task::ready(None);
 6023                if let Some(tasks) = &tasks {
 6024                    if let Some(project) = project {
 6025                        task_context_task =
 6026                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6027                    }
 6028                }
 6029
 6030                cx.spawn_in(window, {
 6031                    let buffer = buffer.clone();
 6032                    async move |editor, cx| {
 6033                        let task_context = task_context_task.await;
 6034
 6035                        let resolved_tasks =
 6036                            tasks
 6037                                .zip(task_context.clone())
 6038                                .map(|(tasks, task_context)| ResolvedTasks {
 6039                                    templates: tasks.resolve(&task_context).collect(),
 6040                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6041                                        multibuffer_point.row,
 6042                                        tasks.column,
 6043                                    )),
 6044                                });
 6045                        let debug_scenarios = editor
 6046                            .update(cx, |editor, cx| {
 6047                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6048                            })?
 6049                            .await;
 6050                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6051                    }
 6052                })
 6053            }
 6054        };
 6055
 6056        cx.spawn_in(window, async move |editor, cx| {
 6057            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6058            let code_actions = code_actions_task.await;
 6059            let spawn_straight_away = quick_launch
 6060                && resolved_tasks
 6061                    .as_ref()
 6062                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6063                && code_actions
 6064                    .as_ref()
 6065                    .map_or(true, |actions| actions.is_empty())
 6066                && debug_scenarios.is_empty();
 6067
 6068            editor.update_in(cx, |editor, window, cx| {
 6069                crate::hover_popover::hide_hover(editor, cx);
 6070                let actions = CodeActionContents::new(
 6071                    resolved_tasks,
 6072                    code_actions,
 6073                    debug_scenarios,
 6074                    task_context.unwrap_or_default(),
 6075                );
 6076
 6077                // Don't show the menu if there are no actions available
 6078                if actions.is_empty() {
 6079                    cx.notify();
 6080                    return Task::ready(Ok(()));
 6081                }
 6082
 6083                *editor.context_menu.borrow_mut() =
 6084                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6085                        buffer,
 6086                        actions,
 6087                        selected_item: Default::default(),
 6088                        scroll_handle: UniformListScrollHandle::default(),
 6089                        deployed_from,
 6090                    }));
 6091                cx.notify();
 6092                if spawn_straight_away {
 6093                    if let Some(task) = editor.confirm_code_action(
 6094                        &ConfirmCodeAction { item_ix: Some(0) },
 6095                        window,
 6096                        cx,
 6097                    ) {
 6098                        return task;
 6099                    }
 6100                }
 6101
 6102                Task::ready(Ok(()))
 6103            })
 6104        })
 6105        .detach_and_log_err(cx);
 6106    }
 6107
 6108    fn debug_scenarios(
 6109        &mut self,
 6110        resolved_tasks: &Option<ResolvedTasks>,
 6111        buffer: &Entity<Buffer>,
 6112        cx: &mut App,
 6113    ) -> Task<Vec<task::DebugScenario>> {
 6114        maybe!({
 6115            let project = self.project.as_ref()?;
 6116            let dap_store = project.read(cx).dap_store();
 6117            let mut scenarios = vec![];
 6118            let resolved_tasks = resolved_tasks.as_ref()?;
 6119            let buffer = buffer.read(cx);
 6120            let language = buffer.language()?;
 6121            let file = buffer.file();
 6122            let debug_adapter = language_settings(language.name().into(), file, cx)
 6123                .debuggers
 6124                .first()
 6125                .map(SharedString::from)
 6126                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6127
 6128            dap_store.update(cx, |dap_store, cx| {
 6129                for (_, task) in &resolved_tasks.templates {
 6130                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6131                        task.original_task().clone(),
 6132                        debug_adapter.clone().into(),
 6133                        task.display_label().to_owned().into(),
 6134                        cx,
 6135                    );
 6136                    scenarios.push(maybe_scenario);
 6137                }
 6138            });
 6139            Some(cx.background_spawn(async move {
 6140                let scenarios = futures::future::join_all(scenarios)
 6141                    .await
 6142                    .into_iter()
 6143                    .flatten()
 6144                    .collect::<Vec<_>>();
 6145                scenarios
 6146            }))
 6147        })
 6148        .unwrap_or_else(|| Task::ready(vec![]))
 6149    }
 6150
 6151    fn code_actions(
 6152        &mut self,
 6153        buffer_row: u32,
 6154        window: &mut Window,
 6155        cx: &mut Context<Self>,
 6156    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6157        let mut task = self.code_actions_task.take();
 6158        cx.spawn_in(window, async move |editor, cx| {
 6159            while let Some(prev_task) = task {
 6160                prev_task.await.log_err();
 6161                task = editor
 6162                    .update(cx, |this, _| this.code_actions_task.take())
 6163                    .ok()?;
 6164            }
 6165
 6166            editor
 6167                .update(cx, |editor, cx| {
 6168                    editor
 6169                        .available_code_actions
 6170                        .clone()
 6171                        .and_then(|(location, code_actions)| {
 6172                            let snapshot = location.buffer.read(cx).snapshot();
 6173                            let point_range = location.range.to_point(&snapshot);
 6174                            let point_range = point_range.start.row..=point_range.end.row;
 6175                            if point_range.contains(&buffer_row) {
 6176                                Some(code_actions)
 6177                            } else {
 6178                                None
 6179                            }
 6180                        })
 6181                })
 6182                .ok()
 6183                .flatten()
 6184        })
 6185    }
 6186
 6187    pub fn confirm_code_action(
 6188        &mut self,
 6189        action: &ConfirmCodeAction,
 6190        window: &mut Window,
 6191        cx: &mut Context<Self>,
 6192    ) -> Option<Task<Result<()>>> {
 6193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6194
 6195        let actions_menu =
 6196            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6197                menu
 6198            } else {
 6199                return None;
 6200            };
 6201
 6202        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6203        let action = actions_menu.actions.get(action_ix)?;
 6204        let title = action.label();
 6205        let buffer = actions_menu.buffer;
 6206        let workspace = self.workspace()?;
 6207
 6208        match action {
 6209            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6210                workspace.update(cx, |workspace, cx| {
 6211                    workspace.schedule_resolved_task(
 6212                        task_source_kind,
 6213                        resolved_task,
 6214                        false,
 6215                        window,
 6216                        cx,
 6217                    );
 6218
 6219                    Some(Task::ready(Ok(())))
 6220                })
 6221            }
 6222            CodeActionsItem::CodeAction {
 6223                excerpt_id,
 6224                action,
 6225                provider,
 6226            } => {
 6227                let apply_code_action =
 6228                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6229                let workspace = workspace.downgrade();
 6230                Some(cx.spawn_in(window, async move |editor, cx| {
 6231                    let project_transaction = apply_code_action.await?;
 6232                    Self::open_project_transaction(
 6233                        &editor,
 6234                        workspace,
 6235                        project_transaction,
 6236                        title,
 6237                        cx,
 6238                    )
 6239                    .await
 6240                }))
 6241            }
 6242            CodeActionsItem::DebugScenario(scenario) => {
 6243                let context = actions_menu.actions.context.clone();
 6244
 6245                workspace.update(cx, |workspace, cx| {
 6246                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6247                    workspace.start_debug_session(
 6248                        scenario,
 6249                        context,
 6250                        Some(buffer),
 6251                        None,
 6252                        window,
 6253                        cx,
 6254                    );
 6255                });
 6256                Some(Task::ready(Ok(())))
 6257            }
 6258        }
 6259    }
 6260
 6261    pub async fn open_project_transaction(
 6262        this: &WeakEntity<Editor>,
 6263        workspace: WeakEntity<Workspace>,
 6264        transaction: ProjectTransaction,
 6265        title: String,
 6266        cx: &mut AsyncWindowContext,
 6267    ) -> Result<()> {
 6268        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6269        cx.update(|_, cx| {
 6270            entries.sort_unstable_by_key(|(buffer, _)| {
 6271                buffer.read(cx).file().map(|f| f.path().clone())
 6272            });
 6273        })?;
 6274
 6275        // If the project transaction's edits are all contained within this editor, then
 6276        // avoid opening a new editor to display them.
 6277
 6278        if let Some((buffer, transaction)) = entries.first() {
 6279            if entries.len() == 1 {
 6280                let excerpt = this.update(cx, |editor, cx| {
 6281                    editor
 6282                        .buffer()
 6283                        .read(cx)
 6284                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6285                })?;
 6286                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6287                    if excerpted_buffer == *buffer {
 6288                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6289                            let excerpt_range = excerpt_range.to_offset(buffer);
 6290                            buffer
 6291                                .edited_ranges_for_transaction::<usize>(transaction)
 6292                                .all(|range| {
 6293                                    excerpt_range.start <= range.start
 6294                                        && excerpt_range.end >= range.end
 6295                                })
 6296                        })?;
 6297
 6298                        if all_edits_within_excerpt {
 6299                            return Ok(());
 6300                        }
 6301                    }
 6302                }
 6303            }
 6304        } else {
 6305            return Ok(());
 6306        }
 6307
 6308        let mut ranges_to_highlight = Vec::new();
 6309        let excerpt_buffer = cx.new(|cx| {
 6310            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6311            for (buffer_handle, transaction) in &entries {
 6312                let edited_ranges = buffer_handle
 6313                    .read(cx)
 6314                    .edited_ranges_for_transaction::<Point>(transaction)
 6315                    .collect::<Vec<_>>();
 6316                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6317                    PathKey::for_buffer(buffer_handle, cx),
 6318                    buffer_handle.clone(),
 6319                    edited_ranges,
 6320                    DEFAULT_MULTIBUFFER_CONTEXT,
 6321                    cx,
 6322                );
 6323
 6324                ranges_to_highlight.extend(ranges);
 6325            }
 6326            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6327            multibuffer
 6328        })?;
 6329
 6330        workspace.update_in(cx, |workspace, window, cx| {
 6331            let project = workspace.project().clone();
 6332            let editor =
 6333                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6334            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6335            editor.update(cx, |editor, cx| {
 6336                editor.highlight_background::<Self>(
 6337                    &ranges_to_highlight,
 6338                    |theme| theme.colors().editor_highlighted_line_background,
 6339                    cx,
 6340                );
 6341            });
 6342        })?;
 6343
 6344        Ok(())
 6345    }
 6346
 6347    pub fn clear_code_action_providers(&mut self) {
 6348        self.code_action_providers.clear();
 6349        self.available_code_actions.take();
 6350    }
 6351
 6352    pub fn add_code_action_provider(
 6353        &mut self,
 6354        provider: Rc<dyn CodeActionProvider>,
 6355        window: &mut Window,
 6356        cx: &mut Context<Self>,
 6357    ) {
 6358        if self
 6359            .code_action_providers
 6360            .iter()
 6361            .any(|existing_provider| existing_provider.id() == provider.id())
 6362        {
 6363            return;
 6364        }
 6365
 6366        self.code_action_providers.push(provider);
 6367        self.refresh_code_actions(window, cx);
 6368    }
 6369
 6370    pub fn remove_code_action_provider(
 6371        &mut self,
 6372        id: Arc<str>,
 6373        window: &mut Window,
 6374        cx: &mut Context<Self>,
 6375    ) {
 6376        self.code_action_providers
 6377            .retain(|provider| provider.id() != id);
 6378        self.refresh_code_actions(window, cx);
 6379    }
 6380
 6381    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6382        !self.code_action_providers.is_empty()
 6383            && EditorSettings::get_global(cx).toolbar.code_actions
 6384    }
 6385
 6386    pub fn has_available_code_actions(&self) -> bool {
 6387        self.available_code_actions
 6388            .as_ref()
 6389            .is_some_and(|(_, actions)| !actions.is_empty())
 6390    }
 6391
 6392    fn render_inline_code_actions(
 6393        &self,
 6394        icon_size: ui::IconSize,
 6395        display_row: DisplayRow,
 6396        is_active: bool,
 6397        cx: &mut Context<Self>,
 6398    ) -> AnyElement {
 6399        let show_tooltip = !self.context_menu_visible();
 6400        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6401            .icon_size(icon_size)
 6402            .shape(ui::IconButtonShape::Square)
 6403            .style(ButtonStyle::Transparent)
 6404            .icon_color(ui::Color::Hidden)
 6405            .toggle_state(is_active)
 6406            .when(show_tooltip, |this| {
 6407                this.tooltip({
 6408                    let focus_handle = self.focus_handle.clone();
 6409                    move |window, cx| {
 6410                        Tooltip::for_action_in(
 6411                            "Toggle Code Actions",
 6412                            &ToggleCodeActions {
 6413                                deployed_from: None,
 6414                                quick_launch: false,
 6415                            },
 6416                            &focus_handle,
 6417                            window,
 6418                            cx,
 6419                        )
 6420                    }
 6421                })
 6422            })
 6423            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6424                window.focus(&editor.focus_handle(cx));
 6425                editor.toggle_code_actions(
 6426                    &crate::actions::ToggleCodeActions {
 6427                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6428                            display_row,
 6429                        )),
 6430                        quick_launch: false,
 6431                    },
 6432                    window,
 6433                    cx,
 6434                );
 6435            }))
 6436            .into_any_element()
 6437    }
 6438
 6439    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6440        &self.context_menu
 6441    }
 6442
 6443    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6444        let newest_selection = self.selections.newest_anchor().clone();
 6445        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6446        let buffer = self.buffer.read(cx);
 6447        if newest_selection.head().diff_base_anchor.is_some() {
 6448            return None;
 6449        }
 6450        let (start_buffer, start) =
 6451            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6452        let (end_buffer, end) =
 6453            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6454        if start_buffer != end_buffer {
 6455            return None;
 6456        }
 6457
 6458        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6459            cx.background_executor()
 6460                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6461                .await;
 6462
 6463            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6464                let providers = this.code_action_providers.clone();
 6465                let tasks = this
 6466                    .code_action_providers
 6467                    .iter()
 6468                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6469                    .collect::<Vec<_>>();
 6470                (providers, tasks)
 6471            })?;
 6472
 6473            let mut actions = Vec::new();
 6474            for (provider, provider_actions) in
 6475                providers.into_iter().zip(future::join_all(tasks).await)
 6476            {
 6477                if let Some(provider_actions) = provider_actions.log_err() {
 6478                    actions.extend(provider_actions.into_iter().map(|action| {
 6479                        AvailableCodeAction {
 6480                            excerpt_id: newest_selection.start.excerpt_id,
 6481                            action,
 6482                            provider: provider.clone(),
 6483                        }
 6484                    }));
 6485                }
 6486            }
 6487
 6488            this.update(cx, |this, cx| {
 6489                this.available_code_actions = if actions.is_empty() {
 6490                    None
 6491                } else {
 6492                    Some((
 6493                        Location {
 6494                            buffer: start_buffer,
 6495                            range: start..end,
 6496                        },
 6497                        actions.into(),
 6498                    ))
 6499                };
 6500                cx.notify();
 6501            })
 6502        }));
 6503        None
 6504    }
 6505
 6506    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6507        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6508            self.show_git_blame_inline = false;
 6509
 6510            self.show_git_blame_inline_delay_task =
 6511                Some(cx.spawn_in(window, async move |this, cx| {
 6512                    cx.background_executor().timer(delay).await;
 6513
 6514                    this.update(cx, |this, cx| {
 6515                        this.show_git_blame_inline = true;
 6516                        cx.notify();
 6517                    })
 6518                    .log_err();
 6519                }));
 6520        }
 6521    }
 6522
 6523    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6524        let snapshot = self.snapshot(window, cx);
 6525        let cursor = self.selections.newest::<Point>(cx).head();
 6526        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6527        else {
 6528            return;
 6529        };
 6530
 6531        let Some(blame) = self.blame.as_ref() else {
 6532            return;
 6533        };
 6534
 6535        let row_info = RowInfo {
 6536            buffer_id: Some(buffer.remote_id()),
 6537            buffer_row: Some(point.row),
 6538            ..Default::default()
 6539        };
 6540        let Some(blame_entry) = blame
 6541            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6542            .flatten()
 6543        else {
 6544            return;
 6545        };
 6546
 6547        let anchor = self.selections.newest_anchor().head();
 6548        let position = self.to_pixel_point(anchor, &snapshot, window);
 6549        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6550            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6551        };
 6552    }
 6553
 6554    fn show_blame_popover(
 6555        &mut self,
 6556        blame_entry: &BlameEntry,
 6557        position: gpui::Point<Pixels>,
 6558        ignore_timeout: bool,
 6559        cx: &mut Context<Self>,
 6560    ) {
 6561        if let Some(state) = &mut self.inline_blame_popover {
 6562            state.hide_task.take();
 6563        } else {
 6564            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6565            let blame_entry = blame_entry.clone();
 6566            let show_task = cx.spawn(async move |editor, cx| {
 6567                if !ignore_timeout {
 6568                    cx.background_executor()
 6569                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6570                        .await;
 6571                }
 6572                editor
 6573                    .update(cx, |editor, cx| {
 6574                        editor.inline_blame_popover_show_task.take();
 6575                        let Some(blame) = editor.blame.as_ref() else {
 6576                            return;
 6577                        };
 6578                        let blame = blame.read(cx);
 6579                        let details = blame.details_for_entry(&blame_entry);
 6580                        let markdown = cx.new(|cx| {
 6581                            Markdown::new(
 6582                                details
 6583                                    .as_ref()
 6584                                    .map(|message| message.message.clone())
 6585                                    .unwrap_or_default(),
 6586                                None,
 6587                                None,
 6588                                cx,
 6589                            )
 6590                        });
 6591                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6592                            position,
 6593                            hide_task: None,
 6594                            popover_bounds: None,
 6595                            popover_state: InlineBlamePopoverState {
 6596                                scroll_handle: ScrollHandle::new(),
 6597                                commit_message: details,
 6598                                markdown,
 6599                            },
 6600                            keyboard_grace: ignore_timeout,
 6601                        });
 6602                        cx.notify();
 6603                    })
 6604                    .ok();
 6605            });
 6606            self.inline_blame_popover_show_task = Some(show_task);
 6607        }
 6608    }
 6609
 6610    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6611        self.inline_blame_popover_show_task.take();
 6612        if let Some(state) = &mut self.inline_blame_popover {
 6613            let hide_task = cx.spawn(async move |editor, cx| {
 6614                cx.background_executor()
 6615                    .timer(std::time::Duration::from_millis(100))
 6616                    .await;
 6617                editor
 6618                    .update(cx, |editor, cx| {
 6619                        editor.inline_blame_popover.take();
 6620                        cx.notify();
 6621                    })
 6622                    .ok();
 6623            });
 6624            state.hide_task = Some(hide_task);
 6625        }
 6626    }
 6627
 6628    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6629        if self.pending_rename.is_some() {
 6630            return None;
 6631        }
 6632
 6633        let provider = self.semantics_provider.clone()?;
 6634        let buffer = self.buffer.read(cx);
 6635        let newest_selection = self.selections.newest_anchor().clone();
 6636        let cursor_position = newest_selection.head();
 6637        let (cursor_buffer, cursor_buffer_position) =
 6638            buffer.text_anchor_for_position(cursor_position, cx)?;
 6639        let (tail_buffer, tail_buffer_position) =
 6640            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6641        if cursor_buffer != tail_buffer {
 6642            return None;
 6643        }
 6644
 6645        let snapshot = cursor_buffer.read(cx).snapshot();
 6646        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6647        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6648        if start_word_range != end_word_range {
 6649            self.document_highlights_task.take();
 6650            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6651            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6652            return None;
 6653        }
 6654
 6655        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6656        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6657            cx.background_executor()
 6658                .timer(Duration::from_millis(debounce))
 6659                .await;
 6660
 6661            let highlights = if let Some(highlights) = cx
 6662                .update(|cx| {
 6663                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6664                })
 6665                .ok()
 6666                .flatten()
 6667            {
 6668                highlights.await.log_err()
 6669            } else {
 6670                None
 6671            };
 6672
 6673            if let Some(highlights) = highlights {
 6674                this.update(cx, |this, cx| {
 6675                    if this.pending_rename.is_some() {
 6676                        return;
 6677                    }
 6678
 6679                    let buffer_id = cursor_position.buffer_id;
 6680                    let buffer = this.buffer.read(cx);
 6681                    if !buffer
 6682                        .text_anchor_for_position(cursor_position, cx)
 6683                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6684                    {
 6685                        return;
 6686                    }
 6687
 6688                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6689                    let mut write_ranges = Vec::new();
 6690                    let mut read_ranges = Vec::new();
 6691                    for highlight in highlights {
 6692                        for (excerpt_id, excerpt_range) in
 6693                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6694                        {
 6695                            let start = highlight
 6696                                .range
 6697                                .start
 6698                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6699                            let end = highlight
 6700                                .range
 6701                                .end
 6702                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6703                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6704                                continue;
 6705                            }
 6706
 6707                            let range = Anchor {
 6708                                buffer_id,
 6709                                excerpt_id,
 6710                                text_anchor: start,
 6711                                diff_base_anchor: None,
 6712                            }..Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: end,
 6716                                diff_base_anchor: None,
 6717                            };
 6718                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6719                                write_ranges.push(range);
 6720                            } else {
 6721                                read_ranges.push(range);
 6722                            }
 6723                        }
 6724                    }
 6725
 6726                    this.highlight_background::<DocumentHighlightRead>(
 6727                        &read_ranges,
 6728                        |theme| theme.colors().editor_document_highlight_read_background,
 6729                        cx,
 6730                    );
 6731                    this.highlight_background::<DocumentHighlightWrite>(
 6732                        &write_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_write_background,
 6734                        cx,
 6735                    );
 6736                    cx.notify();
 6737                })
 6738                .log_err();
 6739            }
 6740        }));
 6741        None
 6742    }
 6743
 6744    fn prepare_highlight_query_from_selection(
 6745        &mut self,
 6746        cx: &mut Context<Editor>,
 6747    ) -> Option<(String, Range<Anchor>)> {
 6748        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6749            return None;
 6750        }
 6751        if !EditorSettings::get_global(cx).selection_highlight {
 6752            return None;
 6753        }
 6754        if self.selections.count() != 1 || self.selections.line_mode {
 6755            return None;
 6756        }
 6757        let selection = self.selections.newest::<Point>(cx);
 6758        if selection.is_empty() || selection.start.row != selection.end.row {
 6759            return None;
 6760        }
 6761        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6762        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6763        let query = multi_buffer_snapshot
 6764            .text_for_range(selection_anchor_range.clone())
 6765            .collect::<String>();
 6766        if query.trim().is_empty() {
 6767            return None;
 6768        }
 6769        Some((query, selection_anchor_range))
 6770    }
 6771
 6772    fn update_selection_occurrence_highlights(
 6773        &mut self,
 6774        query_text: String,
 6775        query_range: Range<Anchor>,
 6776        multi_buffer_range_to_query: Range<Point>,
 6777        use_debounce: bool,
 6778        window: &mut Window,
 6779        cx: &mut Context<Editor>,
 6780    ) -> Task<()> {
 6781        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6782        cx.spawn_in(window, async move |editor, cx| {
 6783            if use_debounce {
 6784                cx.background_executor()
 6785                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6786                    .await;
 6787            }
 6788            let match_task = cx.background_spawn(async move {
 6789                let buffer_ranges = multi_buffer_snapshot
 6790                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6791                    .into_iter()
 6792                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6793                let mut match_ranges = Vec::new();
 6794                let Ok(regex) = project::search::SearchQuery::text(
 6795                    query_text.clone(),
 6796                    false,
 6797                    false,
 6798                    false,
 6799                    Default::default(),
 6800                    Default::default(),
 6801                    false,
 6802                    None,
 6803                ) else {
 6804                    return Vec::default();
 6805                };
 6806                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6807                    match_ranges.extend(
 6808                        regex
 6809                            .search(&buffer_snapshot, Some(search_range.clone()))
 6810                            .await
 6811                            .into_iter()
 6812                            .filter_map(|match_range| {
 6813                                let match_start = buffer_snapshot
 6814                                    .anchor_after(search_range.start + match_range.start);
 6815                                let match_end = buffer_snapshot
 6816                                    .anchor_before(search_range.start + match_range.end);
 6817                                let match_anchor_range = Anchor::range_in_buffer(
 6818                                    excerpt_id,
 6819                                    buffer_snapshot.remote_id(),
 6820                                    match_start..match_end,
 6821                                );
 6822                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6823                            }),
 6824                    );
 6825                }
 6826                match_ranges
 6827            });
 6828            let match_ranges = match_task.await;
 6829            editor
 6830                .update_in(cx, |editor, _, cx| {
 6831                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6832                    if !match_ranges.is_empty() {
 6833                        editor.highlight_background::<SelectedTextHighlight>(
 6834                            &match_ranges,
 6835                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6836                            cx,
 6837                        )
 6838                    }
 6839                })
 6840                .log_err();
 6841        })
 6842    }
 6843
 6844    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6845        struct NewlineFold;
 6846        let type_id = std::any::TypeId::of::<NewlineFold>();
 6847        if !self.mode.is_single_line() {
 6848            return;
 6849        }
 6850        let snapshot = self.snapshot(window, cx);
 6851        if snapshot.buffer_snapshot.max_point().row == 0 {
 6852            return;
 6853        }
 6854        let task = cx.background_spawn(async move {
 6855            let new_newlines = snapshot
 6856                .buffer_chars_at(0)
 6857                .filter_map(|(c, i)| {
 6858                    if c == '\n' {
 6859                        Some(
 6860                            snapshot.buffer_snapshot.anchor_after(i)
 6861                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6862                        )
 6863                    } else {
 6864                        None
 6865                    }
 6866                })
 6867                .collect::<Vec<_>>();
 6868            let existing_newlines = snapshot
 6869                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6870                .filter_map(|fold| {
 6871                    if fold.placeholder.type_tag == Some(type_id) {
 6872                        Some(fold.range.start..fold.range.end)
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878
 6879            (new_newlines, existing_newlines)
 6880        });
 6881        self.folding_newlines = cx.spawn(async move |this, cx| {
 6882            let (new_newlines, existing_newlines) = task.await;
 6883            if new_newlines == existing_newlines {
 6884                return;
 6885            }
 6886            let placeholder = FoldPlaceholder {
 6887                render: Arc::new(move |_, _, cx| {
 6888                    div()
 6889                        .bg(cx.theme().status().hint_background)
 6890                        .border_b_1()
 6891                        .size_full()
 6892                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6893                        .border_color(cx.theme().status().hint)
 6894                        .child("\\n")
 6895                        .into_any()
 6896                }),
 6897                constrain_width: false,
 6898                merge_adjacent: false,
 6899                type_tag: Some(type_id),
 6900            };
 6901            let creases = new_newlines
 6902                .into_iter()
 6903                .map(|range| Crease::simple(range, placeholder.clone()))
 6904                .collect();
 6905            this.update(cx, |this, cx| {
 6906                this.display_map.update(cx, |display_map, cx| {
 6907                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6908                    display_map.fold(creases, cx);
 6909                });
 6910            })
 6911            .ok();
 6912        });
 6913    }
 6914
 6915    fn refresh_selected_text_highlights(
 6916        &mut self,
 6917        on_buffer_edit: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) {
 6921        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6922        else {
 6923            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6924            self.quick_selection_highlight_task.take();
 6925            self.debounced_selection_highlight_task.take();
 6926            return;
 6927        };
 6928        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6929        if on_buffer_edit
 6930            || self
 6931                .quick_selection_highlight_task
 6932                .as_ref()
 6933                .map_or(true, |(prev_anchor_range, _)| {
 6934                    prev_anchor_range != &query_range
 6935                })
 6936        {
 6937            let multi_buffer_visible_start = self
 6938                .scroll_manager
 6939                .anchor()
 6940                .anchor
 6941                .to_point(&multi_buffer_snapshot);
 6942            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6943                multi_buffer_visible_start
 6944                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6945                Bias::Left,
 6946            );
 6947            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6948            self.quick_selection_highlight_task = Some((
 6949                query_range.clone(),
 6950                self.update_selection_occurrence_highlights(
 6951                    query_text.clone(),
 6952                    query_range.clone(),
 6953                    multi_buffer_visible_range,
 6954                    false,
 6955                    window,
 6956                    cx,
 6957                ),
 6958            ));
 6959        }
 6960        if on_buffer_edit
 6961            || self
 6962                .debounced_selection_highlight_task
 6963                .as_ref()
 6964                .map_or(true, |(prev_anchor_range, _)| {
 6965                    prev_anchor_range != &query_range
 6966                })
 6967        {
 6968            let multi_buffer_start = multi_buffer_snapshot
 6969                .anchor_before(0)
 6970                .to_point(&multi_buffer_snapshot);
 6971            let multi_buffer_end = multi_buffer_snapshot
 6972                .anchor_after(multi_buffer_snapshot.len())
 6973                .to_point(&multi_buffer_snapshot);
 6974            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6975            self.debounced_selection_highlight_task = Some((
 6976                query_range.clone(),
 6977                self.update_selection_occurrence_highlights(
 6978                    query_text,
 6979                    query_range,
 6980                    multi_buffer_full_range,
 6981                    true,
 6982                    window,
 6983                    cx,
 6984                ),
 6985            ));
 6986        }
 6987    }
 6988
 6989    pub fn refresh_inline_completion(
 6990        &mut self,
 6991        debounce: bool,
 6992        user_requested: bool,
 6993        window: &mut Window,
 6994        cx: &mut Context<Self>,
 6995    ) -> Option<()> {
 6996        let provider = self.edit_prediction_provider()?;
 6997        let cursor = self.selections.newest_anchor().head();
 6998        let (buffer, cursor_buffer_position) =
 6999            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7000
 7001        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7002            self.discard_inline_completion(false, cx);
 7003            return None;
 7004        }
 7005
 7006        if !user_requested
 7007            && (!self.should_show_edit_predictions()
 7008                || !self.is_focused(window)
 7009                || buffer.read(cx).is_empty())
 7010        {
 7011            self.discard_inline_completion(false, cx);
 7012            return None;
 7013        }
 7014
 7015        self.update_visible_inline_completion(window, cx);
 7016        provider.refresh(
 7017            self.project.clone(),
 7018            buffer,
 7019            cursor_buffer_position,
 7020            debounce,
 7021            cx,
 7022        );
 7023        Some(())
 7024    }
 7025
 7026    fn show_edit_predictions_in_menu(&self) -> bool {
 7027        match self.edit_prediction_settings {
 7028            EditPredictionSettings::Disabled => false,
 7029            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7030        }
 7031    }
 7032
 7033    pub fn edit_predictions_enabled(&self) -> bool {
 7034        match self.edit_prediction_settings {
 7035            EditPredictionSettings::Disabled => false,
 7036            EditPredictionSettings::Enabled { .. } => true,
 7037        }
 7038    }
 7039
 7040    fn edit_prediction_requires_modifier(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled {
 7044                preview_requires_modifier,
 7045                ..
 7046            } => preview_requires_modifier,
 7047        }
 7048    }
 7049
 7050    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7051        if self.edit_prediction_provider.is_none() {
 7052            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7053        } else {
 7054            let selection = self.selections.newest_anchor();
 7055            let cursor = selection.head();
 7056
 7057            if let Some((buffer, cursor_buffer_position)) =
 7058                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7059            {
 7060                self.edit_prediction_settings =
 7061                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7062            }
 7063        }
 7064    }
 7065
 7066    fn edit_prediction_settings_at_position(
 7067        &self,
 7068        buffer: &Entity<Buffer>,
 7069        buffer_position: language::Anchor,
 7070        cx: &App,
 7071    ) -> EditPredictionSettings {
 7072        if !self.mode.is_full()
 7073            || !self.show_inline_completions_override.unwrap_or(true)
 7074            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7075        {
 7076            return EditPredictionSettings::Disabled;
 7077        }
 7078
 7079        let buffer = buffer.read(cx);
 7080
 7081        let file = buffer.file();
 7082
 7083        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7084            return EditPredictionSettings::Disabled;
 7085        };
 7086
 7087        let by_provider = matches!(
 7088            self.menu_inline_completions_policy,
 7089            MenuInlineCompletionsPolicy::ByProvider
 7090        );
 7091
 7092        let show_in_menu = by_provider
 7093            && self
 7094                .edit_prediction_provider
 7095                .as_ref()
 7096                .map_or(false, |provider| {
 7097                    provider.provider.show_completions_in_menu()
 7098                });
 7099
 7100        let preview_requires_modifier =
 7101            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7102
 7103        EditPredictionSettings::Enabled {
 7104            show_in_menu,
 7105            preview_requires_modifier,
 7106        }
 7107    }
 7108
 7109    fn should_show_edit_predictions(&self) -> bool {
 7110        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7111    }
 7112
 7113    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7114        matches!(
 7115            self.edit_prediction_preview,
 7116            EditPredictionPreview::Active { .. }
 7117        )
 7118    }
 7119
 7120    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7121        let cursor = self.selections.newest_anchor().head();
 7122        if let Some((buffer, cursor_position)) =
 7123            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7124        {
 7125            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7126        } else {
 7127            false
 7128        }
 7129    }
 7130
 7131    pub fn supports_minimap(&self, cx: &App) -> bool {
 7132        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7133    }
 7134
 7135    fn edit_predictions_enabled_in_buffer(
 7136        &self,
 7137        buffer: &Entity<Buffer>,
 7138        buffer_position: language::Anchor,
 7139        cx: &App,
 7140    ) -> bool {
 7141        maybe!({
 7142            if self.read_only(cx) {
 7143                return Some(false);
 7144            }
 7145            let provider = self.edit_prediction_provider()?;
 7146            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7147                return Some(false);
 7148            }
 7149            let buffer = buffer.read(cx);
 7150            let Some(file) = buffer.file() else {
 7151                return Some(true);
 7152            };
 7153            let settings = all_language_settings(Some(file), cx);
 7154            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7155        })
 7156        .unwrap_or(false)
 7157    }
 7158
 7159    fn cycle_inline_completion(
 7160        &mut self,
 7161        direction: Direction,
 7162        window: &mut Window,
 7163        cx: &mut Context<Self>,
 7164    ) -> Option<()> {
 7165        let provider = self.edit_prediction_provider()?;
 7166        let cursor = self.selections.newest_anchor().head();
 7167        let (buffer, cursor_buffer_position) =
 7168            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7169        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7170            return None;
 7171        }
 7172
 7173        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7174        self.update_visible_inline_completion(window, cx);
 7175
 7176        Some(())
 7177    }
 7178
 7179    pub fn show_inline_completion(
 7180        &mut self,
 7181        _: &ShowEditPrediction,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) {
 7185        if !self.has_active_inline_completion() {
 7186            self.refresh_inline_completion(false, true, window, cx);
 7187            return;
 7188        }
 7189
 7190        self.update_visible_inline_completion(window, cx);
 7191    }
 7192
 7193    pub fn display_cursor_names(
 7194        &mut self,
 7195        _: &DisplayCursorNames,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) {
 7199        self.show_cursor_names(window, cx);
 7200    }
 7201
 7202    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7203        self.show_cursor_names = true;
 7204        cx.notify();
 7205        cx.spawn_in(window, async move |this, cx| {
 7206            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7207            this.update(cx, |this, cx| {
 7208                this.show_cursor_names = false;
 7209                cx.notify()
 7210            })
 7211            .ok()
 7212        })
 7213        .detach();
 7214    }
 7215
 7216    pub fn next_edit_prediction(
 7217        &mut self,
 7218        _: &NextEditPrediction,
 7219        window: &mut Window,
 7220        cx: &mut Context<Self>,
 7221    ) {
 7222        if self.has_active_inline_completion() {
 7223            self.cycle_inline_completion(Direction::Next, window, cx);
 7224        } else {
 7225            let is_copilot_disabled = self
 7226                .refresh_inline_completion(false, true, window, cx)
 7227                .is_none();
 7228            if is_copilot_disabled {
 7229                cx.propagate();
 7230            }
 7231        }
 7232    }
 7233
 7234    pub fn previous_edit_prediction(
 7235        &mut self,
 7236        _: &PreviousEditPrediction,
 7237        window: &mut Window,
 7238        cx: &mut Context<Self>,
 7239    ) {
 7240        if self.has_active_inline_completion() {
 7241            self.cycle_inline_completion(Direction::Prev, window, cx);
 7242        } else {
 7243            let is_copilot_disabled = self
 7244                .refresh_inline_completion(false, true, window, cx)
 7245                .is_none();
 7246            if is_copilot_disabled {
 7247                cx.propagate();
 7248            }
 7249        }
 7250    }
 7251
 7252    pub fn accept_edit_prediction(
 7253        &mut self,
 7254        _: &AcceptEditPrediction,
 7255        window: &mut Window,
 7256        cx: &mut Context<Self>,
 7257    ) {
 7258        if self.show_edit_predictions_in_menu() {
 7259            self.hide_context_menu(window, cx);
 7260        }
 7261
 7262        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7263            return;
 7264        };
 7265
 7266        self.report_inline_completion_event(
 7267            active_inline_completion.completion_id.clone(),
 7268            true,
 7269            cx,
 7270        );
 7271
 7272        match &active_inline_completion.completion {
 7273            InlineCompletion::Move { target, .. } => {
 7274                let target = *target;
 7275
 7276                if let Some(position_map) = &self.last_position_map {
 7277                    if position_map
 7278                        .visible_row_range
 7279                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7280                        || !self.edit_prediction_requires_modifier()
 7281                    {
 7282                        self.unfold_ranges(&[target..target], true, false, cx);
 7283                        // Note that this is also done in vim's handler of the Tab action.
 7284                        self.change_selections(
 7285                            SelectionEffects::scroll(Autoscroll::newest()),
 7286                            window,
 7287                            cx,
 7288                            |selections| {
 7289                                selections.select_anchor_ranges([target..target]);
 7290                            },
 7291                        );
 7292                        self.clear_row_highlights::<EditPredictionPreview>();
 7293
 7294                        self.edit_prediction_preview
 7295                            .set_previous_scroll_position(None);
 7296                    } else {
 7297                        self.edit_prediction_preview
 7298                            .set_previous_scroll_position(Some(
 7299                                position_map.snapshot.scroll_anchor,
 7300                            ));
 7301
 7302                        self.highlight_rows::<EditPredictionPreview>(
 7303                            target..target,
 7304                            cx.theme().colors().editor_highlighted_line_background,
 7305                            RowHighlightOptions {
 7306                                autoscroll: true,
 7307                                ..Default::default()
 7308                            },
 7309                            cx,
 7310                        );
 7311                        self.request_autoscroll(Autoscroll::fit(), cx);
 7312                    }
 7313                }
 7314            }
 7315            InlineCompletion::Edit { edits, .. } => {
 7316                if let Some(provider) = self.edit_prediction_provider() {
 7317                    provider.accept(cx);
 7318                }
 7319
 7320                // Store the transaction ID and selections before applying the edit
 7321                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7322
 7323                let snapshot = self.buffer.read(cx).snapshot(cx);
 7324                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7325
 7326                self.buffer.update(cx, |buffer, cx| {
 7327                    buffer.edit(edits.iter().cloned(), None, cx)
 7328                });
 7329
 7330                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7331                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7332                });
 7333
 7334                let selections = self.selections.disjoint_anchors();
 7335                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7336                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7337                    if has_new_transaction {
 7338                        self.selection_history
 7339                            .insert_transaction(transaction_id_now, selections);
 7340                    }
 7341                }
 7342
 7343                self.update_visible_inline_completion(window, cx);
 7344                if self.active_inline_completion.is_none() {
 7345                    self.refresh_inline_completion(true, true, window, cx);
 7346                }
 7347
 7348                cx.notify();
 7349            }
 7350        }
 7351
 7352        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7353    }
 7354
 7355    pub fn accept_partial_inline_completion(
 7356        &mut self,
 7357        _: &AcceptPartialEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7362            return;
 7363        };
 7364        if self.selections.count() != 1 {
 7365            return;
 7366        }
 7367
 7368        self.report_inline_completion_event(
 7369            active_inline_completion.completion_id.clone(),
 7370            true,
 7371            cx,
 7372        );
 7373
 7374        match &active_inline_completion.completion {
 7375            InlineCompletion::Move { target, .. } => {
 7376                let target = *target;
 7377                self.change_selections(
 7378                    SelectionEffects::scroll(Autoscroll::newest()),
 7379                    window,
 7380                    cx,
 7381                    |selections| {
 7382                        selections.select_anchor_ranges([target..target]);
 7383                    },
 7384                );
 7385            }
 7386            InlineCompletion::Edit { edits, .. } => {
 7387                // Find an insertion that starts at the cursor position.
 7388                let snapshot = self.buffer.read(cx).snapshot(cx);
 7389                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7390                let insertion = edits.iter().find_map(|(range, text)| {
 7391                    let range = range.to_offset(&snapshot);
 7392                    if range.is_empty() && range.start == cursor_offset {
 7393                        Some(text)
 7394                    } else {
 7395                        None
 7396                    }
 7397                });
 7398
 7399                if let Some(text) = insertion {
 7400                    let mut partial_completion = text
 7401                        .chars()
 7402                        .by_ref()
 7403                        .take_while(|c| c.is_alphabetic())
 7404                        .collect::<String>();
 7405                    if partial_completion.is_empty() {
 7406                        partial_completion = text
 7407                            .chars()
 7408                            .by_ref()
 7409                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7410                            .collect::<String>();
 7411                    }
 7412
 7413                    cx.emit(EditorEvent::InputHandled {
 7414                        utf16_range_to_replace: None,
 7415                        text: partial_completion.clone().into(),
 7416                    });
 7417
 7418                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7419
 7420                    self.refresh_inline_completion(true, true, window, cx);
 7421                    cx.notify();
 7422                } else {
 7423                    self.accept_edit_prediction(&Default::default(), window, cx);
 7424                }
 7425            }
 7426        }
 7427    }
 7428
 7429    fn discard_inline_completion(
 7430        &mut self,
 7431        should_report_inline_completion_event: bool,
 7432        cx: &mut Context<Self>,
 7433    ) -> bool {
 7434        if should_report_inline_completion_event {
 7435            let completion_id = self
 7436                .active_inline_completion
 7437                .as_ref()
 7438                .and_then(|active_completion| active_completion.completion_id.clone());
 7439
 7440            self.report_inline_completion_event(completion_id, false, cx);
 7441        }
 7442
 7443        if let Some(provider) = self.edit_prediction_provider() {
 7444            provider.discard(cx);
 7445        }
 7446
 7447        self.take_active_inline_completion(cx)
 7448    }
 7449
 7450    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7451        let Some(provider) = self.edit_prediction_provider() else {
 7452            return;
 7453        };
 7454
 7455        let Some((_, buffer, _)) = self
 7456            .buffer
 7457            .read(cx)
 7458            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7459        else {
 7460            return;
 7461        };
 7462
 7463        let extension = buffer
 7464            .read(cx)
 7465            .file()
 7466            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7467
 7468        let event_type = match accepted {
 7469            true => "Edit Prediction Accepted",
 7470            false => "Edit Prediction Discarded",
 7471        };
 7472        telemetry::event!(
 7473            event_type,
 7474            provider = provider.name(),
 7475            prediction_id = id,
 7476            suggestion_accepted = accepted,
 7477            file_extension = extension,
 7478        );
 7479    }
 7480
 7481    pub fn has_active_inline_completion(&self) -> bool {
 7482        self.active_inline_completion.is_some()
 7483    }
 7484
 7485    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7486        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7487            return false;
 7488        };
 7489
 7490        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7491        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7492        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7493        true
 7494    }
 7495
 7496    /// Returns true when we're displaying the edit prediction popover below the cursor
 7497    /// like we are not previewing and the LSP autocomplete menu is visible
 7498    /// or we are in `when_holding_modifier` mode.
 7499    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7500        if self.edit_prediction_preview_is_active()
 7501            || !self.show_edit_predictions_in_menu()
 7502            || !self.edit_predictions_enabled()
 7503        {
 7504            return false;
 7505        }
 7506
 7507        if self.has_visible_completions_menu() {
 7508            return true;
 7509        }
 7510
 7511        has_completion && self.edit_prediction_requires_modifier()
 7512    }
 7513
 7514    fn handle_modifiers_changed(
 7515        &mut self,
 7516        modifiers: Modifiers,
 7517        position_map: &PositionMap,
 7518        window: &mut Window,
 7519        cx: &mut Context<Self>,
 7520    ) {
 7521        if self.show_edit_predictions_in_menu() {
 7522            self.update_edit_prediction_preview(&modifiers, window, cx);
 7523        }
 7524
 7525        self.update_selection_mode(&modifiers, position_map, window, cx);
 7526
 7527        let mouse_position = window.mouse_position();
 7528        if !position_map.text_hitbox.is_hovered(window) {
 7529            return;
 7530        }
 7531
 7532        self.update_hovered_link(
 7533            position_map.point_for_position(mouse_position),
 7534            &position_map.snapshot,
 7535            modifiers,
 7536            window,
 7537            cx,
 7538        )
 7539    }
 7540
 7541    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7542        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7543        if invert {
 7544            match multi_cursor_setting {
 7545                MultiCursorModifier::Alt => modifiers.alt,
 7546                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7547            }
 7548        } else {
 7549            match multi_cursor_setting {
 7550                MultiCursorModifier::Alt => modifiers.secondary(),
 7551                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7552            }
 7553        }
 7554    }
 7555
 7556    fn columnar_selection_mode(
 7557        modifiers: &Modifiers,
 7558        cx: &mut Context<Self>,
 7559    ) -> Option<ColumnarMode> {
 7560        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7561            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7562                Some(ColumnarMode::FromMouse)
 7563            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7564                Some(ColumnarMode::FromSelection)
 7565            } else {
 7566                None
 7567            }
 7568        } else {
 7569            None
 7570        }
 7571    }
 7572
 7573    fn update_selection_mode(
 7574        &mut self,
 7575        modifiers: &Modifiers,
 7576        position_map: &PositionMap,
 7577        window: &mut Window,
 7578        cx: &mut Context<Self>,
 7579    ) {
 7580        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7581            return;
 7582        };
 7583        if self.selections.pending.is_none() {
 7584            return;
 7585        }
 7586
 7587        let mouse_position = window.mouse_position();
 7588        let point_for_position = position_map.point_for_position(mouse_position);
 7589        let position = point_for_position.previous_valid;
 7590
 7591        self.select(
 7592            SelectPhase::BeginColumnar {
 7593                position,
 7594                reset: false,
 7595                mode,
 7596                goal_column: point_for_position.exact_unclipped.column(),
 7597            },
 7598            window,
 7599            cx,
 7600        );
 7601    }
 7602
 7603    fn update_edit_prediction_preview(
 7604        &mut self,
 7605        modifiers: &Modifiers,
 7606        window: &mut Window,
 7607        cx: &mut Context<Self>,
 7608    ) {
 7609        let mut modifiers_held = false;
 7610        if let Some(accept_keystroke) = self
 7611            .accept_edit_prediction_keybind(false, window, cx)
 7612            .keystroke()
 7613        {
 7614            modifiers_held = modifiers_held
 7615                || (&accept_keystroke.modifiers == modifiers
 7616                    && accept_keystroke.modifiers.modified());
 7617        };
 7618        if let Some(accept_partial_keystroke) = self
 7619            .accept_edit_prediction_keybind(true, window, cx)
 7620            .keystroke()
 7621        {
 7622            modifiers_held = modifiers_held
 7623                || (&accept_partial_keystroke.modifiers == modifiers
 7624                    && accept_partial_keystroke.modifiers.modified());
 7625        }
 7626
 7627        if modifiers_held {
 7628            if matches!(
 7629                self.edit_prediction_preview,
 7630                EditPredictionPreview::Inactive { .. }
 7631            ) {
 7632                self.edit_prediction_preview = EditPredictionPreview::Active {
 7633                    previous_scroll_position: None,
 7634                    since: Instant::now(),
 7635                };
 7636
 7637                self.update_visible_inline_completion(window, cx);
 7638                cx.notify();
 7639            }
 7640        } else if let EditPredictionPreview::Active {
 7641            previous_scroll_position,
 7642            since,
 7643        } = self.edit_prediction_preview
 7644        {
 7645            if let (Some(previous_scroll_position), Some(position_map)) =
 7646                (previous_scroll_position, self.last_position_map.as_ref())
 7647            {
 7648                self.set_scroll_position(
 7649                    previous_scroll_position
 7650                        .scroll_position(&position_map.snapshot.display_snapshot),
 7651                    window,
 7652                    cx,
 7653                );
 7654            }
 7655
 7656            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7657                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7658            };
 7659            self.clear_row_highlights::<EditPredictionPreview>();
 7660            self.update_visible_inline_completion(window, cx);
 7661            cx.notify();
 7662        }
 7663    }
 7664
 7665    fn update_visible_inline_completion(
 7666        &mut self,
 7667        _window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) -> Option<()> {
 7670        let selection = self.selections.newest_anchor();
 7671        let cursor = selection.head();
 7672        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7673        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7674        let excerpt_id = cursor.excerpt_id;
 7675
 7676        let show_in_menu = self.show_edit_predictions_in_menu();
 7677        let completions_menu_has_precedence = !show_in_menu
 7678            && (self.context_menu.borrow().is_some()
 7679                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7680
 7681        if completions_menu_has_precedence
 7682            || !offset_selection.is_empty()
 7683            || self
 7684                .active_inline_completion
 7685                .as_ref()
 7686                .map_or(false, |completion| {
 7687                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7688                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7689                    !invalidation_range.contains(&offset_selection.head())
 7690                })
 7691        {
 7692            self.discard_inline_completion(false, cx);
 7693            return None;
 7694        }
 7695
 7696        self.take_active_inline_completion(cx);
 7697        let Some(provider) = self.edit_prediction_provider() else {
 7698            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7699            return None;
 7700        };
 7701
 7702        let (buffer, cursor_buffer_position) =
 7703            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7704
 7705        self.edit_prediction_settings =
 7706            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7707
 7708        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7709
 7710        if self.edit_prediction_indent_conflict {
 7711            let cursor_point = cursor.to_point(&multibuffer);
 7712
 7713            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7714
 7715            if let Some((_, indent)) = indents.iter().next() {
 7716                if indent.len == cursor_point.column {
 7717                    self.edit_prediction_indent_conflict = false;
 7718                }
 7719            }
 7720        }
 7721
 7722        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7723        let edits = inline_completion
 7724            .edits
 7725            .into_iter()
 7726            .flat_map(|(range, new_text)| {
 7727                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7728                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7729                Some((start..end, new_text))
 7730            })
 7731            .collect::<Vec<_>>();
 7732        if edits.is_empty() {
 7733            return None;
 7734        }
 7735
 7736        let first_edit_start = edits.first().unwrap().0.start;
 7737        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7738        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7739
 7740        let last_edit_end = edits.last().unwrap().0.end;
 7741        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7742        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7743
 7744        let cursor_row = cursor.to_point(&multibuffer).row;
 7745
 7746        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7747
 7748        let mut inlay_ids = Vec::new();
 7749        let invalidation_row_range;
 7750        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7751            Some(cursor_row..edit_end_row)
 7752        } else if cursor_row > edit_end_row {
 7753            Some(edit_start_row..cursor_row)
 7754        } else {
 7755            None
 7756        };
 7757        let is_move =
 7758            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7759        let completion = if is_move {
 7760            invalidation_row_range =
 7761                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7762            let target = first_edit_start;
 7763            InlineCompletion::Move { target, snapshot }
 7764        } else {
 7765            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7766                && !self.inline_completions_hidden_for_vim_mode;
 7767
 7768            if show_completions_in_buffer {
 7769                if edits
 7770                    .iter()
 7771                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7772                {
 7773                    let mut inlays = Vec::new();
 7774                    for (range, new_text) in &edits {
 7775                        let inlay = Inlay::inline_completion(
 7776                            post_inc(&mut self.next_inlay_id),
 7777                            range.start,
 7778                            new_text.as_str(),
 7779                        );
 7780                        inlay_ids.push(inlay.id);
 7781                        inlays.push(inlay);
 7782                    }
 7783
 7784                    self.splice_inlays(&[], inlays, cx);
 7785                } else {
 7786                    let background_color = cx.theme().status().deleted_background;
 7787                    self.highlight_text::<InlineCompletionHighlight>(
 7788                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7789                        HighlightStyle {
 7790                            background_color: Some(background_color),
 7791                            ..Default::default()
 7792                        },
 7793                        cx,
 7794                    );
 7795                }
 7796            }
 7797
 7798            invalidation_row_range = edit_start_row..edit_end_row;
 7799
 7800            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7801                if provider.show_tab_accept_marker() {
 7802                    EditDisplayMode::TabAccept
 7803                } else {
 7804                    EditDisplayMode::Inline
 7805                }
 7806            } else {
 7807                EditDisplayMode::DiffPopover
 7808            };
 7809
 7810            InlineCompletion::Edit {
 7811                edits,
 7812                edit_preview: inline_completion.edit_preview,
 7813                display_mode,
 7814                snapshot,
 7815            }
 7816        };
 7817
 7818        let invalidation_range = multibuffer
 7819            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7820            ..multibuffer.anchor_after(Point::new(
 7821                invalidation_row_range.end,
 7822                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7823            ));
 7824
 7825        self.stale_inline_completion_in_menu = None;
 7826        self.active_inline_completion = Some(InlineCompletionState {
 7827            inlay_ids,
 7828            completion,
 7829            completion_id: inline_completion.id,
 7830            invalidation_range,
 7831        });
 7832
 7833        cx.notify();
 7834
 7835        Some(())
 7836    }
 7837
 7838    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7839        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7840    }
 7841
 7842    fn clear_tasks(&mut self) {
 7843        self.tasks.clear()
 7844    }
 7845
 7846    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7847        if self.tasks.insert(key, value).is_some() {
 7848            // This case should hopefully be rare, but just in case...
 7849            log::error!(
 7850                "multiple different run targets found on a single line, only the last target will be rendered"
 7851            )
 7852        }
 7853    }
 7854
 7855    /// Get all display points of breakpoints that will be rendered within editor
 7856    ///
 7857    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7858    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7859    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7860    fn active_breakpoints(
 7861        &self,
 7862        range: Range<DisplayRow>,
 7863        window: &mut Window,
 7864        cx: &mut Context<Self>,
 7865    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7866        let mut breakpoint_display_points = HashMap::default();
 7867
 7868        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7869            return breakpoint_display_points;
 7870        };
 7871
 7872        let snapshot = self.snapshot(window, cx);
 7873
 7874        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7875        let Some(project) = self.project.as_ref() else {
 7876            return breakpoint_display_points;
 7877        };
 7878
 7879        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7880            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7881
 7882        for (buffer_snapshot, range, excerpt_id) in
 7883            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7884        {
 7885            let Some(buffer) = project
 7886                .read(cx)
 7887                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7888            else {
 7889                continue;
 7890            };
 7891            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7892                &buffer,
 7893                Some(
 7894                    buffer_snapshot.anchor_before(range.start)
 7895                        ..buffer_snapshot.anchor_after(range.end),
 7896                ),
 7897                buffer_snapshot,
 7898                cx,
 7899            );
 7900            for (breakpoint, state) in breakpoints {
 7901                let multi_buffer_anchor =
 7902                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7903                let position = multi_buffer_anchor
 7904                    .to_point(&multi_buffer_snapshot)
 7905                    .to_display_point(&snapshot);
 7906
 7907                breakpoint_display_points.insert(
 7908                    position.row(),
 7909                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7910                );
 7911            }
 7912        }
 7913
 7914        breakpoint_display_points
 7915    }
 7916
 7917    fn breakpoint_context_menu(
 7918        &self,
 7919        anchor: Anchor,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) -> Entity<ui::ContextMenu> {
 7923        let weak_editor = cx.weak_entity();
 7924        let focus_handle = self.focus_handle(cx);
 7925
 7926        let row = self
 7927            .buffer
 7928            .read(cx)
 7929            .snapshot(cx)
 7930            .summary_for_anchor::<Point>(&anchor)
 7931            .row;
 7932
 7933        let breakpoint = self
 7934            .breakpoint_at_row(row, window, cx)
 7935            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7936
 7937        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7938            "Edit Log Breakpoint"
 7939        } else {
 7940            "Set Log Breakpoint"
 7941        };
 7942
 7943        let condition_breakpoint_msg = if breakpoint
 7944            .as_ref()
 7945            .is_some_and(|bp| bp.1.condition.is_some())
 7946        {
 7947            "Edit Condition Breakpoint"
 7948        } else {
 7949            "Set Condition Breakpoint"
 7950        };
 7951
 7952        let hit_condition_breakpoint_msg = if breakpoint
 7953            .as_ref()
 7954            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7955        {
 7956            "Edit Hit Condition Breakpoint"
 7957        } else {
 7958            "Set Hit Condition Breakpoint"
 7959        };
 7960
 7961        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7962            "Unset Breakpoint"
 7963        } else {
 7964            "Set Breakpoint"
 7965        };
 7966
 7967        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7968
 7969        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7970            BreakpointState::Enabled => Some("Disable"),
 7971            BreakpointState::Disabled => Some("Enable"),
 7972        });
 7973
 7974        let (anchor, breakpoint) =
 7975            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7976
 7977        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7978            menu.on_blur_subscription(Subscription::new(|| {}))
 7979                .context(focus_handle)
 7980                .when(run_to_cursor, |this| {
 7981                    let weak_editor = weak_editor.clone();
 7982                    this.entry("Run to cursor", None, move |window, cx| {
 7983                        weak_editor
 7984                            .update(cx, |editor, cx| {
 7985                                editor.change_selections(
 7986                                    SelectionEffects::no_scroll(),
 7987                                    window,
 7988                                    cx,
 7989                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7990                                );
 7991                            })
 7992                            .ok();
 7993
 7994                        window.dispatch_action(Box::new(RunToCursor), cx);
 7995                    })
 7996                    .separator()
 7997                })
 7998                .when_some(toggle_state_msg, |this, msg| {
 7999                    this.entry(msg, None, {
 8000                        let weak_editor = weak_editor.clone();
 8001                        let breakpoint = breakpoint.clone();
 8002                        move |_window, cx| {
 8003                            weak_editor
 8004                                .update(cx, |this, cx| {
 8005                                    this.edit_breakpoint_at_anchor(
 8006                                        anchor,
 8007                                        breakpoint.as_ref().clone(),
 8008                                        BreakpointEditAction::InvertState,
 8009                                        cx,
 8010                                    );
 8011                                })
 8012                                .log_err();
 8013                        }
 8014                    })
 8015                })
 8016                .entry(set_breakpoint_msg, None, {
 8017                    let weak_editor = weak_editor.clone();
 8018                    let breakpoint = breakpoint.clone();
 8019                    move |_window, cx| {
 8020                        weak_editor
 8021                            .update(cx, |this, cx| {
 8022                                this.edit_breakpoint_at_anchor(
 8023                                    anchor,
 8024                                    breakpoint.as_ref().clone(),
 8025                                    BreakpointEditAction::Toggle,
 8026                                    cx,
 8027                                );
 8028                            })
 8029                            .log_err();
 8030                    }
 8031                })
 8032                .entry(log_breakpoint_msg, None, {
 8033                    let breakpoint = breakpoint.clone();
 8034                    let weak_editor = weak_editor.clone();
 8035                    move |window, cx| {
 8036                        weak_editor
 8037                            .update(cx, |this, cx| {
 8038                                this.add_edit_breakpoint_block(
 8039                                    anchor,
 8040                                    breakpoint.as_ref(),
 8041                                    BreakpointPromptEditAction::Log,
 8042                                    window,
 8043                                    cx,
 8044                                );
 8045                            })
 8046                            .log_err();
 8047                    }
 8048                })
 8049                .entry(condition_breakpoint_msg, None, {
 8050                    let breakpoint = breakpoint.clone();
 8051                    let weak_editor = weak_editor.clone();
 8052                    move |window, cx| {
 8053                        weak_editor
 8054                            .update(cx, |this, cx| {
 8055                                this.add_edit_breakpoint_block(
 8056                                    anchor,
 8057                                    breakpoint.as_ref(),
 8058                                    BreakpointPromptEditAction::Condition,
 8059                                    window,
 8060                                    cx,
 8061                                );
 8062                            })
 8063                            .log_err();
 8064                    }
 8065                })
 8066                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8067                    weak_editor
 8068                        .update(cx, |this, cx| {
 8069                            this.add_edit_breakpoint_block(
 8070                                anchor,
 8071                                breakpoint.as_ref(),
 8072                                BreakpointPromptEditAction::HitCondition,
 8073                                window,
 8074                                cx,
 8075                            );
 8076                        })
 8077                        .log_err();
 8078                })
 8079        })
 8080    }
 8081
 8082    fn render_breakpoint(
 8083        &self,
 8084        position: Anchor,
 8085        row: DisplayRow,
 8086        breakpoint: &Breakpoint,
 8087        state: Option<BreakpointSessionState>,
 8088        cx: &mut Context<Self>,
 8089    ) -> IconButton {
 8090        let is_rejected = state.is_some_and(|s| !s.verified);
 8091        // Is it a breakpoint that shows up when hovering over gutter?
 8092        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8093            (false, false),
 8094            |PhantomBreakpointIndicator {
 8095                 is_active,
 8096                 display_row,
 8097                 collides_with_existing_breakpoint,
 8098             }| {
 8099                (
 8100                    is_active && display_row == row,
 8101                    collides_with_existing_breakpoint,
 8102                )
 8103            },
 8104        );
 8105
 8106        let (color, icon) = {
 8107            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8108                (false, false) => ui::IconName::DebugBreakpoint,
 8109                (true, false) => ui::IconName::DebugLogBreakpoint,
 8110                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8111                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8112            };
 8113
 8114            let color = if is_phantom {
 8115                Color::Hint
 8116            } else if is_rejected {
 8117                Color::Disabled
 8118            } else {
 8119                Color::Debugger
 8120            };
 8121
 8122            (color, icon)
 8123        };
 8124
 8125        let breakpoint = Arc::from(breakpoint.clone());
 8126
 8127        let alt_as_text = gpui::Keystroke {
 8128            modifiers: Modifiers::secondary_key(),
 8129            ..Default::default()
 8130        };
 8131        let primary_action_text = if breakpoint.is_disabled() {
 8132            "Enable breakpoint"
 8133        } else if is_phantom && !collides_with_existing {
 8134            "Set breakpoint"
 8135        } else {
 8136            "Unset breakpoint"
 8137        };
 8138        let focus_handle = self.focus_handle.clone();
 8139
 8140        let meta = if is_rejected {
 8141            SharedString::from("No executable code is associated with this line.")
 8142        } else if collides_with_existing && !breakpoint.is_disabled() {
 8143            SharedString::from(format!(
 8144                "{alt_as_text}-click to disable,\nright-click for more options."
 8145            ))
 8146        } else {
 8147            SharedString::from("Right-click for more options.")
 8148        };
 8149        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8150            .icon_size(IconSize::XSmall)
 8151            .size(ui::ButtonSize::None)
 8152            .when(is_rejected, |this| {
 8153                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8154            })
 8155            .icon_color(color)
 8156            .style(ButtonStyle::Transparent)
 8157            .on_click(cx.listener({
 8158                let breakpoint = breakpoint.clone();
 8159
 8160                move |editor, event: &ClickEvent, window, cx| {
 8161                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8162                        BreakpointEditAction::InvertState
 8163                    } else {
 8164                        BreakpointEditAction::Toggle
 8165                    };
 8166
 8167                    window.focus(&editor.focus_handle(cx));
 8168                    editor.edit_breakpoint_at_anchor(
 8169                        position,
 8170                        breakpoint.as_ref().clone(),
 8171                        edit_action,
 8172                        cx,
 8173                    );
 8174                }
 8175            }))
 8176            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8177                editor.set_breakpoint_context_menu(
 8178                    row,
 8179                    Some(position),
 8180                    event.down.position,
 8181                    window,
 8182                    cx,
 8183                );
 8184            }))
 8185            .tooltip(move |window, cx| {
 8186                Tooltip::with_meta_in(
 8187                    primary_action_text,
 8188                    Some(&ToggleBreakpoint),
 8189                    meta.clone(),
 8190                    &focus_handle,
 8191                    window,
 8192                    cx,
 8193                )
 8194            })
 8195    }
 8196
 8197    fn build_tasks_context(
 8198        project: &Entity<Project>,
 8199        buffer: &Entity<Buffer>,
 8200        buffer_row: u32,
 8201        tasks: &Arc<RunnableTasks>,
 8202        cx: &mut Context<Self>,
 8203    ) -> Task<Option<task::TaskContext>> {
 8204        let position = Point::new(buffer_row, tasks.column);
 8205        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8206        let location = Location {
 8207            buffer: buffer.clone(),
 8208            range: range_start..range_start,
 8209        };
 8210        // Fill in the environmental variables from the tree-sitter captures
 8211        let mut captured_task_variables = TaskVariables::default();
 8212        for (capture_name, value) in tasks.extra_variables.clone() {
 8213            captured_task_variables.insert(
 8214                task::VariableName::Custom(capture_name.into()),
 8215                value.clone(),
 8216            );
 8217        }
 8218        project.update(cx, |project, cx| {
 8219            project.task_store().update(cx, |task_store, cx| {
 8220                task_store.task_context_for_location(captured_task_variables, location, cx)
 8221            })
 8222        })
 8223    }
 8224
 8225    pub fn spawn_nearest_task(
 8226        &mut self,
 8227        action: &SpawnNearestTask,
 8228        window: &mut Window,
 8229        cx: &mut Context<Self>,
 8230    ) {
 8231        let Some((workspace, _)) = self.workspace.clone() else {
 8232            return;
 8233        };
 8234        let Some(project) = self.project.clone() else {
 8235            return;
 8236        };
 8237
 8238        // Try to find a closest, enclosing node using tree-sitter that has a task
 8239        let Some((buffer, buffer_row, tasks)) = self
 8240            .find_enclosing_node_task(cx)
 8241            // Or find the task that's closest in row-distance.
 8242            .or_else(|| self.find_closest_task(cx))
 8243        else {
 8244            return;
 8245        };
 8246
 8247        let reveal_strategy = action.reveal;
 8248        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8249        cx.spawn_in(window, async move |_, cx| {
 8250            let context = task_context.await?;
 8251            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8252
 8253            let resolved = &mut resolved_task.resolved;
 8254            resolved.reveal = reveal_strategy;
 8255
 8256            workspace
 8257                .update_in(cx, |workspace, window, cx| {
 8258                    workspace.schedule_resolved_task(
 8259                        task_source_kind,
 8260                        resolved_task,
 8261                        false,
 8262                        window,
 8263                        cx,
 8264                    );
 8265                })
 8266                .ok()
 8267        })
 8268        .detach();
 8269    }
 8270
 8271    fn find_closest_task(
 8272        &mut self,
 8273        cx: &mut Context<Self>,
 8274    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8275        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8276
 8277        let ((buffer_id, row), tasks) = self
 8278            .tasks
 8279            .iter()
 8280            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8281
 8282        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8283        let tasks = Arc::new(tasks.to_owned());
 8284        Some((buffer, *row, tasks))
 8285    }
 8286
 8287    fn find_enclosing_node_task(
 8288        &mut self,
 8289        cx: &mut Context<Self>,
 8290    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8291        let snapshot = self.buffer.read(cx).snapshot(cx);
 8292        let offset = self.selections.newest::<usize>(cx).head();
 8293        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8294        let buffer_id = excerpt.buffer().remote_id();
 8295
 8296        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8297        let mut cursor = layer.node().walk();
 8298
 8299        while cursor.goto_first_child_for_byte(offset).is_some() {
 8300            if cursor.node().end_byte() == offset {
 8301                cursor.goto_next_sibling();
 8302            }
 8303        }
 8304
 8305        // Ascend to the smallest ancestor that contains the range and has a task.
 8306        loop {
 8307            let node = cursor.node();
 8308            let node_range = node.byte_range();
 8309            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8310
 8311            // Check if this node contains our offset
 8312            if node_range.start <= offset && node_range.end >= offset {
 8313                // If it contains offset, check for task
 8314                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8315                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8316                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8317                }
 8318            }
 8319
 8320            if !cursor.goto_parent() {
 8321                break;
 8322            }
 8323        }
 8324        None
 8325    }
 8326
 8327    fn render_run_indicator(
 8328        &self,
 8329        _style: &EditorStyle,
 8330        is_active: bool,
 8331        row: DisplayRow,
 8332        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8333        cx: &mut Context<Self>,
 8334    ) -> IconButton {
 8335        let color = Color::Muted;
 8336        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8337
 8338        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8339            .shape(ui::IconButtonShape::Square)
 8340            .icon_size(IconSize::XSmall)
 8341            .icon_color(color)
 8342            .toggle_state(is_active)
 8343            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8344                let quick_launch = e.down.button == MouseButton::Left;
 8345                window.focus(&editor.focus_handle(cx));
 8346                editor.toggle_code_actions(
 8347                    &ToggleCodeActions {
 8348                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8349                        quick_launch,
 8350                    },
 8351                    window,
 8352                    cx,
 8353                );
 8354            }))
 8355            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8356                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8357            }))
 8358    }
 8359
 8360    pub fn context_menu_visible(&self) -> bool {
 8361        !self.edit_prediction_preview_is_active()
 8362            && self
 8363                .context_menu
 8364                .borrow()
 8365                .as_ref()
 8366                .map_or(false, |menu| menu.visible())
 8367    }
 8368
 8369    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8370        self.context_menu
 8371            .borrow()
 8372            .as_ref()
 8373            .map(|menu| menu.origin())
 8374    }
 8375
 8376    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8377        self.context_menu_options = Some(options);
 8378    }
 8379
 8380    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8381    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8382
 8383    fn render_edit_prediction_popover(
 8384        &mut self,
 8385        text_bounds: &Bounds<Pixels>,
 8386        content_origin: gpui::Point<Pixels>,
 8387        right_margin: Pixels,
 8388        editor_snapshot: &EditorSnapshot,
 8389        visible_row_range: Range<DisplayRow>,
 8390        scroll_top: f32,
 8391        scroll_bottom: f32,
 8392        line_layouts: &[LineWithInvisibles],
 8393        line_height: Pixels,
 8394        scroll_pixel_position: gpui::Point<Pixels>,
 8395        newest_selection_head: Option<DisplayPoint>,
 8396        editor_width: Pixels,
 8397        style: &EditorStyle,
 8398        window: &mut Window,
 8399        cx: &mut App,
 8400    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8401        if self.mode().is_minimap() {
 8402            return None;
 8403        }
 8404        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8405
 8406        if self.edit_prediction_visible_in_cursor_popover(true) {
 8407            return None;
 8408        }
 8409
 8410        match &active_inline_completion.completion {
 8411            InlineCompletion::Move { target, .. } => {
 8412                let target_display_point = target.to_display_point(editor_snapshot);
 8413
 8414                if self.edit_prediction_requires_modifier() {
 8415                    if !self.edit_prediction_preview_is_active() {
 8416                        return None;
 8417                    }
 8418
 8419                    self.render_edit_prediction_modifier_jump_popover(
 8420                        text_bounds,
 8421                        content_origin,
 8422                        visible_row_range,
 8423                        line_layouts,
 8424                        line_height,
 8425                        scroll_pixel_position,
 8426                        newest_selection_head,
 8427                        target_display_point,
 8428                        window,
 8429                        cx,
 8430                    )
 8431                } else {
 8432                    self.render_edit_prediction_eager_jump_popover(
 8433                        text_bounds,
 8434                        content_origin,
 8435                        editor_snapshot,
 8436                        visible_row_range,
 8437                        scroll_top,
 8438                        scroll_bottom,
 8439                        line_height,
 8440                        scroll_pixel_position,
 8441                        target_display_point,
 8442                        editor_width,
 8443                        window,
 8444                        cx,
 8445                    )
 8446                }
 8447            }
 8448            InlineCompletion::Edit {
 8449                display_mode: EditDisplayMode::Inline,
 8450                ..
 8451            } => None,
 8452            InlineCompletion::Edit {
 8453                display_mode: EditDisplayMode::TabAccept,
 8454                edits,
 8455                ..
 8456            } => {
 8457                let range = &edits.first()?.0;
 8458                let target_display_point = range.end.to_display_point(editor_snapshot);
 8459
 8460                self.render_edit_prediction_end_of_line_popover(
 8461                    "Accept",
 8462                    editor_snapshot,
 8463                    visible_row_range,
 8464                    target_display_point,
 8465                    line_height,
 8466                    scroll_pixel_position,
 8467                    content_origin,
 8468                    editor_width,
 8469                    window,
 8470                    cx,
 8471                )
 8472            }
 8473            InlineCompletion::Edit {
 8474                edits,
 8475                edit_preview,
 8476                display_mode: EditDisplayMode::DiffPopover,
 8477                snapshot,
 8478            } => self.render_edit_prediction_diff_popover(
 8479                text_bounds,
 8480                content_origin,
 8481                right_margin,
 8482                editor_snapshot,
 8483                visible_row_range,
 8484                line_layouts,
 8485                line_height,
 8486                scroll_pixel_position,
 8487                newest_selection_head,
 8488                editor_width,
 8489                style,
 8490                edits,
 8491                edit_preview,
 8492                snapshot,
 8493                window,
 8494                cx,
 8495            ),
 8496        }
 8497    }
 8498
 8499    fn render_edit_prediction_modifier_jump_popover(
 8500        &mut self,
 8501        text_bounds: &Bounds<Pixels>,
 8502        content_origin: gpui::Point<Pixels>,
 8503        visible_row_range: Range<DisplayRow>,
 8504        line_layouts: &[LineWithInvisibles],
 8505        line_height: Pixels,
 8506        scroll_pixel_position: gpui::Point<Pixels>,
 8507        newest_selection_head: Option<DisplayPoint>,
 8508        target_display_point: DisplayPoint,
 8509        window: &mut Window,
 8510        cx: &mut App,
 8511    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8512        let scrolled_content_origin =
 8513            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8514
 8515        const SCROLL_PADDING_Y: Pixels = px(12.);
 8516
 8517        if target_display_point.row() < visible_row_range.start {
 8518            return self.render_edit_prediction_scroll_popover(
 8519                |_| SCROLL_PADDING_Y,
 8520                IconName::ArrowUp,
 8521                visible_row_range,
 8522                line_layouts,
 8523                newest_selection_head,
 8524                scrolled_content_origin,
 8525                window,
 8526                cx,
 8527            );
 8528        } else if target_display_point.row() >= visible_row_range.end {
 8529            return self.render_edit_prediction_scroll_popover(
 8530                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8531                IconName::ArrowDown,
 8532                visible_row_range,
 8533                line_layouts,
 8534                newest_selection_head,
 8535                scrolled_content_origin,
 8536                window,
 8537                cx,
 8538            );
 8539        }
 8540
 8541        const POLE_WIDTH: Pixels = px(2.);
 8542
 8543        let line_layout =
 8544            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8545        let target_column = target_display_point.column() as usize;
 8546
 8547        let target_x = line_layout.x_for_index(target_column);
 8548        let target_y =
 8549            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8550
 8551        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8552
 8553        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8554        border_color.l += 0.001;
 8555
 8556        let mut element = v_flex()
 8557            .items_end()
 8558            .when(flag_on_right, |el| el.items_start())
 8559            .child(if flag_on_right {
 8560                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8561                    .rounded_bl(px(0.))
 8562                    .rounded_tl(px(0.))
 8563                    .border_l_2()
 8564                    .border_color(border_color)
 8565            } else {
 8566                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8567                    .rounded_br(px(0.))
 8568                    .rounded_tr(px(0.))
 8569                    .border_r_2()
 8570                    .border_color(border_color)
 8571            })
 8572            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8573            .into_any();
 8574
 8575        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8576
 8577        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8578            - point(
 8579                if flag_on_right {
 8580                    POLE_WIDTH
 8581                } else {
 8582                    size.width - POLE_WIDTH
 8583                },
 8584                size.height - line_height,
 8585            );
 8586
 8587        origin.x = origin.x.max(content_origin.x);
 8588
 8589        element.prepaint_at(origin, window, cx);
 8590
 8591        Some((element, origin))
 8592    }
 8593
 8594    fn render_edit_prediction_scroll_popover(
 8595        &mut self,
 8596        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8597        scroll_icon: IconName,
 8598        visible_row_range: Range<DisplayRow>,
 8599        line_layouts: &[LineWithInvisibles],
 8600        newest_selection_head: Option<DisplayPoint>,
 8601        scrolled_content_origin: gpui::Point<Pixels>,
 8602        window: &mut Window,
 8603        cx: &mut App,
 8604    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8605        let mut element = self
 8606            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8607            .into_any();
 8608
 8609        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8610
 8611        let cursor = newest_selection_head?;
 8612        let cursor_row_layout =
 8613            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8614        let cursor_column = cursor.column() as usize;
 8615
 8616        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8617
 8618        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8619
 8620        element.prepaint_at(origin, window, cx);
 8621        Some((element, origin))
 8622    }
 8623
 8624    fn render_edit_prediction_eager_jump_popover(
 8625        &mut self,
 8626        text_bounds: &Bounds<Pixels>,
 8627        content_origin: gpui::Point<Pixels>,
 8628        editor_snapshot: &EditorSnapshot,
 8629        visible_row_range: Range<DisplayRow>,
 8630        scroll_top: f32,
 8631        scroll_bottom: f32,
 8632        line_height: Pixels,
 8633        scroll_pixel_position: gpui::Point<Pixels>,
 8634        target_display_point: DisplayPoint,
 8635        editor_width: Pixels,
 8636        window: &mut Window,
 8637        cx: &mut App,
 8638    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8639        if target_display_point.row().as_f32() < scroll_top {
 8640            let mut element = self
 8641                .render_edit_prediction_line_popover(
 8642                    "Jump to Edit",
 8643                    Some(IconName::ArrowUp),
 8644                    window,
 8645                    cx,
 8646                )?
 8647                .into_any();
 8648
 8649            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8650            let offset = point(
 8651                (text_bounds.size.width - size.width) / 2.,
 8652                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8653            );
 8654
 8655            let origin = text_bounds.origin + offset;
 8656            element.prepaint_at(origin, window, cx);
 8657            Some((element, origin))
 8658        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8659            let mut element = self
 8660                .render_edit_prediction_line_popover(
 8661                    "Jump to Edit",
 8662                    Some(IconName::ArrowDown),
 8663                    window,
 8664                    cx,
 8665                )?
 8666                .into_any();
 8667
 8668            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8669            let offset = point(
 8670                (text_bounds.size.width - size.width) / 2.,
 8671                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8672            );
 8673
 8674            let origin = text_bounds.origin + offset;
 8675            element.prepaint_at(origin, window, cx);
 8676            Some((element, origin))
 8677        } else {
 8678            self.render_edit_prediction_end_of_line_popover(
 8679                "Jump to Edit",
 8680                editor_snapshot,
 8681                visible_row_range,
 8682                target_display_point,
 8683                line_height,
 8684                scroll_pixel_position,
 8685                content_origin,
 8686                editor_width,
 8687                window,
 8688                cx,
 8689            )
 8690        }
 8691    }
 8692
 8693    fn render_edit_prediction_end_of_line_popover(
 8694        self: &mut Editor,
 8695        label: &'static str,
 8696        editor_snapshot: &EditorSnapshot,
 8697        visible_row_range: Range<DisplayRow>,
 8698        target_display_point: DisplayPoint,
 8699        line_height: Pixels,
 8700        scroll_pixel_position: gpui::Point<Pixels>,
 8701        content_origin: gpui::Point<Pixels>,
 8702        editor_width: Pixels,
 8703        window: &mut Window,
 8704        cx: &mut App,
 8705    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8706        let target_line_end = DisplayPoint::new(
 8707            target_display_point.row(),
 8708            editor_snapshot.line_len(target_display_point.row()),
 8709        );
 8710
 8711        let mut element = self
 8712            .render_edit_prediction_line_popover(label, None, window, cx)?
 8713            .into_any();
 8714
 8715        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8716
 8717        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8718
 8719        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8720        let mut origin = start_point
 8721            + line_origin
 8722            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8723        origin.x = origin.x.max(content_origin.x);
 8724
 8725        let max_x = content_origin.x + editor_width - size.width;
 8726
 8727        if origin.x > max_x {
 8728            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8729
 8730            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8731                origin.y += offset;
 8732                IconName::ArrowUp
 8733            } else {
 8734                origin.y -= offset;
 8735                IconName::ArrowDown
 8736            };
 8737
 8738            element = self
 8739                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8740                .into_any();
 8741
 8742            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8743
 8744            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8745        }
 8746
 8747        element.prepaint_at(origin, window, cx);
 8748        Some((element, origin))
 8749    }
 8750
 8751    fn render_edit_prediction_diff_popover(
 8752        self: &Editor,
 8753        text_bounds: &Bounds<Pixels>,
 8754        content_origin: gpui::Point<Pixels>,
 8755        right_margin: Pixels,
 8756        editor_snapshot: &EditorSnapshot,
 8757        visible_row_range: Range<DisplayRow>,
 8758        line_layouts: &[LineWithInvisibles],
 8759        line_height: Pixels,
 8760        scroll_pixel_position: gpui::Point<Pixels>,
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        editor_width: Pixels,
 8763        style: &EditorStyle,
 8764        edits: &Vec<(Range<Anchor>, String)>,
 8765        edit_preview: &Option<language::EditPreview>,
 8766        snapshot: &language::BufferSnapshot,
 8767        window: &mut Window,
 8768        cx: &mut App,
 8769    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8770        let edit_start = edits
 8771            .first()
 8772            .unwrap()
 8773            .0
 8774            .start
 8775            .to_display_point(editor_snapshot);
 8776        let edit_end = edits
 8777            .last()
 8778            .unwrap()
 8779            .0
 8780            .end
 8781            .to_display_point(editor_snapshot);
 8782
 8783        let is_visible = visible_row_range.contains(&edit_start.row())
 8784            || visible_row_range.contains(&edit_end.row());
 8785        if !is_visible {
 8786            return None;
 8787        }
 8788
 8789        let highlighted_edits =
 8790            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8791
 8792        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8793        let line_count = highlighted_edits.text.lines().count();
 8794
 8795        const BORDER_WIDTH: Pixels = px(1.);
 8796
 8797        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8798        let has_keybind = keybind.is_some();
 8799
 8800        let mut element = h_flex()
 8801            .items_start()
 8802            .child(
 8803                h_flex()
 8804                    .bg(cx.theme().colors().editor_background)
 8805                    .border(BORDER_WIDTH)
 8806                    .shadow_xs()
 8807                    .border_color(cx.theme().colors().border)
 8808                    .rounded_l_lg()
 8809                    .when(line_count > 1, |el| el.rounded_br_lg())
 8810                    .pr_1()
 8811                    .child(styled_text),
 8812            )
 8813            .child(
 8814                h_flex()
 8815                    .h(line_height + BORDER_WIDTH * 2.)
 8816                    .px_1p5()
 8817                    .gap_1()
 8818                    // Workaround: For some reason, there's a gap if we don't do this
 8819                    .ml(-BORDER_WIDTH)
 8820                    .shadow(vec![gpui::BoxShadow {
 8821                        color: gpui::black().opacity(0.05),
 8822                        offset: point(px(1.), px(1.)),
 8823                        blur_radius: px(2.),
 8824                        spread_radius: px(0.),
 8825                    }])
 8826                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8827                    .border(BORDER_WIDTH)
 8828                    .border_color(cx.theme().colors().border)
 8829                    .rounded_r_lg()
 8830                    .id("edit_prediction_diff_popover_keybind")
 8831                    .when(!has_keybind, |el| {
 8832                        let status_colors = cx.theme().status();
 8833
 8834                        el.bg(status_colors.error_background)
 8835                            .border_color(status_colors.error.opacity(0.6))
 8836                            .child(Icon::new(IconName::Info).color(Color::Error))
 8837                            .cursor_default()
 8838                            .hoverable_tooltip(move |_window, cx| {
 8839                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8840                            })
 8841                    })
 8842                    .children(keybind),
 8843            )
 8844            .into_any();
 8845
 8846        let longest_row =
 8847            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8848        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8849            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8850        } else {
 8851            layout_line(
 8852                longest_row,
 8853                editor_snapshot,
 8854                style,
 8855                editor_width,
 8856                |_| false,
 8857                window,
 8858                cx,
 8859            )
 8860            .width
 8861        };
 8862
 8863        let viewport_bounds =
 8864            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8865                right: -right_margin,
 8866                ..Default::default()
 8867            });
 8868
 8869        let x_after_longest =
 8870            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8871                - scroll_pixel_position.x;
 8872
 8873        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8874
 8875        // Fully visible if it can be displayed within the window (allow overlapping other
 8876        // panes). However, this is only allowed if the popover starts within text_bounds.
 8877        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8878            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8879
 8880        let mut origin = if can_position_to_the_right {
 8881            point(
 8882                x_after_longest,
 8883                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8884                    - scroll_pixel_position.y,
 8885            )
 8886        } else {
 8887            let cursor_row = newest_selection_head.map(|head| head.row());
 8888            let above_edit = edit_start
 8889                .row()
 8890                .0
 8891                .checked_sub(line_count as u32)
 8892                .map(DisplayRow);
 8893            let below_edit = Some(edit_end.row() + 1);
 8894            let above_cursor =
 8895                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8896            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8897
 8898            // Place the edit popover adjacent to the edit if there is a location
 8899            // available that is onscreen and does not obscure the cursor. Otherwise,
 8900            // place it adjacent to the cursor.
 8901            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8902                .into_iter()
 8903                .flatten()
 8904                .find(|&start_row| {
 8905                    let end_row = start_row + line_count as u32;
 8906                    visible_row_range.contains(&start_row)
 8907                        && visible_row_range.contains(&end_row)
 8908                        && cursor_row.map_or(true, |cursor_row| {
 8909                            !((start_row..end_row).contains(&cursor_row))
 8910                        })
 8911                })?;
 8912
 8913            content_origin
 8914                + point(
 8915                    -scroll_pixel_position.x,
 8916                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8917                )
 8918        };
 8919
 8920        origin.x -= BORDER_WIDTH;
 8921
 8922        window.defer_draw(element, origin, 1);
 8923
 8924        // Do not return an element, since it will already be drawn due to defer_draw.
 8925        None
 8926    }
 8927
 8928    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8929        px(30.)
 8930    }
 8931
 8932    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8933        if self.read_only(cx) {
 8934            cx.theme().players().read_only()
 8935        } else {
 8936            self.style.as_ref().unwrap().local_player
 8937        }
 8938    }
 8939
 8940    fn render_edit_prediction_accept_keybind(
 8941        &self,
 8942        window: &mut Window,
 8943        cx: &App,
 8944    ) -> Option<AnyElement> {
 8945        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8946        let accept_keystroke = accept_binding.keystroke()?;
 8947
 8948        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8949
 8950        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8951            Color::Accent
 8952        } else {
 8953            Color::Muted
 8954        };
 8955
 8956        h_flex()
 8957            .px_0p5()
 8958            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8959            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8960            .text_size(TextSize::XSmall.rems(cx))
 8961            .child(h_flex().children(ui::render_modifiers(
 8962                &accept_keystroke.modifiers,
 8963                PlatformStyle::platform(),
 8964                Some(modifiers_color),
 8965                Some(IconSize::XSmall.rems().into()),
 8966                true,
 8967            )))
 8968            .when(is_platform_style_mac, |parent| {
 8969                parent.child(accept_keystroke.key.clone())
 8970            })
 8971            .when(!is_platform_style_mac, |parent| {
 8972                parent.child(
 8973                    Key::new(
 8974                        util::capitalize(&accept_keystroke.key),
 8975                        Some(Color::Default),
 8976                    )
 8977                    .size(Some(IconSize::XSmall.rems().into())),
 8978                )
 8979            })
 8980            .into_any()
 8981            .into()
 8982    }
 8983
 8984    fn render_edit_prediction_line_popover(
 8985        &self,
 8986        label: impl Into<SharedString>,
 8987        icon: Option<IconName>,
 8988        window: &mut Window,
 8989        cx: &App,
 8990    ) -> Option<Stateful<Div>> {
 8991        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8992
 8993        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8994        let has_keybind = keybind.is_some();
 8995
 8996        let result = h_flex()
 8997            .id("ep-line-popover")
 8998            .py_0p5()
 8999            .pl_1()
 9000            .pr(padding_right)
 9001            .gap_1()
 9002            .rounded_md()
 9003            .border_1()
 9004            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9005            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9006            .shadow_xs()
 9007            .when(!has_keybind, |el| {
 9008                let status_colors = cx.theme().status();
 9009
 9010                el.bg(status_colors.error_background)
 9011                    .border_color(status_colors.error.opacity(0.6))
 9012                    .pl_2()
 9013                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9014                    .cursor_default()
 9015                    .hoverable_tooltip(move |_window, cx| {
 9016                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9017                    })
 9018            })
 9019            .children(keybind)
 9020            .child(
 9021                Label::new(label)
 9022                    .size(LabelSize::Small)
 9023                    .when(!has_keybind, |el| {
 9024                        el.color(cx.theme().status().error.into()).strikethrough()
 9025                    }),
 9026            )
 9027            .when(!has_keybind, |el| {
 9028                el.child(
 9029                    h_flex().ml_1().child(
 9030                        Icon::new(IconName::Info)
 9031                            .size(IconSize::Small)
 9032                            .color(cx.theme().status().error.into()),
 9033                    ),
 9034                )
 9035            })
 9036            .when_some(icon, |element, icon| {
 9037                element.child(
 9038                    div()
 9039                        .mt(px(1.5))
 9040                        .child(Icon::new(icon).size(IconSize::Small)),
 9041                )
 9042            });
 9043
 9044        Some(result)
 9045    }
 9046
 9047    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9048        let accent_color = cx.theme().colors().text_accent;
 9049        let editor_bg_color = cx.theme().colors().editor_background;
 9050        editor_bg_color.blend(accent_color.opacity(0.1))
 9051    }
 9052
 9053    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9054        let accent_color = cx.theme().colors().text_accent;
 9055        let editor_bg_color = cx.theme().colors().editor_background;
 9056        editor_bg_color.blend(accent_color.opacity(0.6))
 9057    }
 9058
 9059    fn render_edit_prediction_cursor_popover(
 9060        &self,
 9061        min_width: Pixels,
 9062        max_width: Pixels,
 9063        cursor_point: Point,
 9064        style: &EditorStyle,
 9065        accept_keystroke: Option<&gpui::Keystroke>,
 9066        _window: &Window,
 9067        cx: &mut Context<Editor>,
 9068    ) -> Option<AnyElement> {
 9069        let provider = self.edit_prediction_provider.as_ref()?;
 9070
 9071        if provider.provider.needs_terms_acceptance(cx) {
 9072            return Some(
 9073                h_flex()
 9074                    .min_w(min_width)
 9075                    .flex_1()
 9076                    .px_2()
 9077                    .py_1()
 9078                    .gap_3()
 9079                    .elevation_2(cx)
 9080                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9081                    .id("accept-terms")
 9082                    .cursor_pointer()
 9083                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9084                    .on_click(cx.listener(|this, _event, window, cx| {
 9085                        cx.stop_propagation();
 9086                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9087                        window.dispatch_action(
 9088                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9089                            cx,
 9090                        );
 9091                    }))
 9092                    .child(
 9093                        h_flex()
 9094                            .flex_1()
 9095                            .gap_2()
 9096                            .child(Icon::new(IconName::ZedPredict))
 9097                            .child(Label::new("Accept Terms of Service"))
 9098                            .child(div().w_full())
 9099                            .child(
 9100                                Icon::new(IconName::ArrowUpRight)
 9101                                    .color(Color::Muted)
 9102                                    .size(IconSize::Small),
 9103                            )
 9104                            .into_any_element(),
 9105                    )
 9106                    .into_any(),
 9107            );
 9108        }
 9109
 9110        let is_refreshing = provider.provider.is_refreshing(cx);
 9111
 9112        fn pending_completion_container() -> Div {
 9113            h_flex()
 9114                .h_full()
 9115                .flex_1()
 9116                .gap_2()
 9117                .child(Icon::new(IconName::ZedPredict))
 9118        }
 9119
 9120        let completion = match &self.active_inline_completion {
 9121            Some(prediction) => {
 9122                if !self.has_visible_completions_menu() {
 9123                    const RADIUS: Pixels = px(6.);
 9124                    const BORDER_WIDTH: Pixels = px(1.);
 9125
 9126                    return Some(
 9127                        h_flex()
 9128                            .elevation_2(cx)
 9129                            .border(BORDER_WIDTH)
 9130                            .border_color(cx.theme().colors().border)
 9131                            .when(accept_keystroke.is_none(), |el| {
 9132                                el.border_color(cx.theme().status().error)
 9133                            })
 9134                            .rounded(RADIUS)
 9135                            .rounded_tl(px(0.))
 9136                            .overflow_hidden()
 9137                            .child(div().px_1p5().child(match &prediction.completion {
 9138                                InlineCompletion::Move { target, snapshot } => {
 9139                                    use text::ToPoint as _;
 9140                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9141                                    {
 9142                                        Icon::new(IconName::ZedPredictDown)
 9143                                    } else {
 9144                                        Icon::new(IconName::ZedPredictUp)
 9145                                    }
 9146                                }
 9147                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9148                            }))
 9149                            .child(
 9150                                h_flex()
 9151                                    .gap_1()
 9152                                    .py_1()
 9153                                    .px_2()
 9154                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9155                                    .border_l_1()
 9156                                    .border_color(cx.theme().colors().border)
 9157                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9158                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9159                                        el.child(
 9160                                            Label::new("Hold")
 9161                                                .size(LabelSize::Small)
 9162                                                .when(accept_keystroke.is_none(), |el| {
 9163                                                    el.strikethrough()
 9164                                                })
 9165                                                .line_height_style(LineHeightStyle::UiLabel),
 9166                                        )
 9167                                    })
 9168                                    .id("edit_prediction_cursor_popover_keybind")
 9169                                    .when(accept_keystroke.is_none(), |el| {
 9170                                        let status_colors = cx.theme().status();
 9171
 9172                                        el.bg(status_colors.error_background)
 9173                                            .border_color(status_colors.error.opacity(0.6))
 9174                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9175                                            .cursor_default()
 9176                                            .hoverable_tooltip(move |_window, cx| {
 9177                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9178                                                    .into()
 9179                                            })
 9180                                    })
 9181                                    .when_some(
 9182                                        accept_keystroke.as_ref(),
 9183                                        |el, accept_keystroke| {
 9184                                            el.child(h_flex().children(ui::render_modifiers(
 9185                                                &accept_keystroke.modifiers,
 9186                                                PlatformStyle::platform(),
 9187                                                Some(Color::Default),
 9188                                                Some(IconSize::XSmall.rems().into()),
 9189                                                false,
 9190                                            )))
 9191                                        },
 9192                                    ),
 9193                            )
 9194                            .into_any(),
 9195                    );
 9196                }
 9197
 9198                self.render_edit_prediction_cursor_popover_preview(
 9199                    prediction,
 9200                    cursor_point,
 9201                    style,
 9202                    cx,
 9203                )?
 9204            }
 9205
 9206            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9207                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9208                    stale_completion,
 9209                    cursor_point,
 9210                    style,
 9211                    cx,
 9212                )?,
 9213
 9214                None => {
 9215                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9216                }
 9217            },
 9218
 9219            None => pending_completion_container().child(Label::new("No Prediction")),
 9220        };
 9221
 9222        let completion = if is_refreshing {
 9223            completion
 9224                .with_animation(
 9225                    "loading-completion",
 9226                    Animation::new(Duration::from_secs(2))
 9227                        .repeat()
 9228                        .with_easing(pulsating_between(0.4, 0.8)),
 9229                    |label, delta| label.opacity(delta),
 9230                )
 9231                .into_any_element()
 9232        } else {
 9233            completion.into_any_element()
 9234        };
 9235
 9236        let has_completion = self.active_inline_completion.is_some();
 9237
 9238        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9239        Some(
 9240            h_flex()
 9241                .min_w(min_width)
 9242                .max_w(max_width)
 9243                .flex_1()
 9244                .elevation_2(cx)
 9245                .border_color(cx.theme().colors().border)
 9246                .child(
 9247                    div()
 9248                        .flex_1()
 9249                        .py_1()
 9250                        .px_2()
 9251                        .overflow_hidden()
 9252                        .child(completion),
 9253                )
 9254                .when_some(accept_keystroke, |el, accept_keystroke| {
 9255                    if !accept_keystroke.modifiers.modified() {
 9256                        return el;
 9257                    }
 9258
 9259                    el.child(
 9260                        h_flex()
 9261                            .h_full()
 9262                            .border_l_1()
 9263                            .rounded_r_lg()
 9264                            .border_color(cx.theme().colors().border)
 9265                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9266                            .gap_1()
 9267                            .py_1()
 9268                            .px_2()
 9269                            .child(
 9270                                h_flex()
 9271                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9272                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9273                                    .child(h_flex().children(ui::render_modifiers(
 9274                                        &accept_keystroke.modifiers,
 9275                                        PlatformStyle::platform(),
 9276                                        Some(if !has_completion {
 9277                                            Color::Muted
 9278                                        } else {
 9279                                            Color::Default
 9280                                        }),
 9281                                        None,
 9282                                        false,
 9283                                    ))),
 9284                            )
 9285                            .child(Label::new("Preview").into_any_element())
 9286                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9287                    )
 9288                })
 9289                .into_any(),
 9290        )
 9291    }
 9292
 9293    fn render_edit_prediction_cursor_popover_preview(
 9294        &self,
 9295        completion: &InlineCompletionState,
 9296        cursor_point: Point,
 9297        style: &EditorStyle,
 9298        cx: &mut Context<Editor>,
 9299    ) -> Option<Div> {
 9300        use text::ToPoint as _;
 9301
 9302        fn render_relative_row_jump(
 9303            prefix: impl Into<String>,
 9304            current_row: u32,
 9305            target_row: u32,
 9306        ) -> Div {
 9307            let (row_diff, arrow) = if target_row < current_row {
 9308                (current_row - target_row, IconName::ArrowUp)
 9309            } else {
 9310                (target_row - current_row, IconName::ArrowDown)
 9311            };
 9312
 9313            h_flex()
 9314                .child(
 9315                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9316                        .color(Color::Muted)
 9317                        .size(LabelSize::Small),
 9318                )
 9319                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9320        }
 9321
 9322        match &completion.completion {
 9323            InlineCompletion::Move {
 9324                target, snapshot, ..
 9325            } => Some(
 9326                h_flex()
 9327                    .px_2()
 9328                    .gap_2()
 9329                    .flex_1()
 9330                    .child(
 9331                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9332                            Icon::new(IconName::ZedPredictDown)
 9333                        } else {
 9334                            Icon::new(IconName::ZedPredictUp)
 9335                        },
 9336                    )
 9337                    .child(Label::new("Jump to Edit")),
 9338            ),
 9339
 9340            InlineCompletion::Edit {
 9341                edits,
 9342                edit_preview,
 9343                snapshot,
 9344                display_mode: _,
 9345            } => {
 9346                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9347
 9348                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9349                    &snapshot,
 9350                    &edits,
 9351                    edit_preview.as_ref()?,
 9352                    true,
 9353                    cx,
 9354                )
 9355                .first_line_preview();
 9356
 9357                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9358                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9359
 9360                let preview = h_flex()
 9361                    .gap_1()
 9362                    .min_w_16()
 9363                    .child(styled_text)
 9364                    .when(has_more_lines, |parent| parent.child(""));
 9365
 9366                let left = if first_edit_row != cursor_point.row {
 9367                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9368                        .into_any_element()
 9369                } else {
 9370                    Icon::new(IconName::ZedPredict).into_any_element()
 9371                };
 9372
 9373                Some(
 9374                    h_flex()
 9375                        .h_full()
 9376                        .flex_1()
 9377                        .gap_2()
 9378                        .pr_1()
 9379                        .overflow_x_hidden()
 9380                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9381                        .child(left)
 9382                        .child(preview),
 9383                )
 9384            }
 9385        }
 9386    }
 9387
 9388    pub fn render_context_menu(
 9389        &self,
 9390        style: &EditorStyle,
 9391        max_height_in_lines: u32,
 9392        window: &mut Window,
 9393        cx: &mut Context<Editor>,
 9394    ) -> Option<AnyElement> {
 9395        let menu = self.context_menu.borrow();
 9396        let menu = menu.as_ref()?;
 9397        if !menu.visible() {
 9398            return None;
 9399        };
 9400        Some(menu.render(style, max_height_in_lines, window, cx))
 9401    }
 9402
 9403    fn render_context_menu_aside(
 9404        &mut self,
 9405        max_size: Size<Pixels>,
 9406        window: &mut Window,
 9407        cx: &mut Context<Editor>,
 9408    ) -> Option<AnyElement> {
 9409        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9410            if menu.visible() {
 9411                menu.render_aside(max_size, window, cx)
 9412            } else {
 9413                None
 9414            }
 9415        })
 9416    }
 9417
 9418    fn hide_context_menu(
 9419        &mut self,
 9420        window: &mut Window,
 9421        cx: &mut Context<Self>,
 9422    ) -> Option<CodeContextMenu> {
 9423        cx.notify();
 9424        self.completion_tasks.clear();
 9425        let context_menu = self.context_menu.borrow_mut().take();
 9426        self.stale_inline_completion_in_menu.take();
 9427        self.update_visible_inline_completion(window, cx);
 9428        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9429            if let Some(completion_provider) = &self.completion_provider {
 9430                completion_provider.selection_changed(None, window, cx);
 9431            }
 9432        }
 9433        context_menu
 9434    }
 9435
 9436    fn show_snippet_choices(
 9437        &mut self,
 9438        choices: &Vec<String>,
 9439        selection: Range<Anchor>,
 9440        cx: &mut Context<Self>,
 9441    ) {
 9442        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9443            (Some(a), Some(b)) if a == b => a,
 9444            _ => {
 9445                log::error!("expected anchor range to have matching buffer IDs");
 9446                return;
 9447            }
 9448        };
 9449        let multi_buffer = self.buffer().read(cx);
 9450        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9451            return;
 9452        };
 9453
 9454        let id = post_inc(&mut self.next_completion_id);
 9455        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9456        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9457            CompletionsMenu::new_snippet_choices(
 9458                id,
 9459                true,
 9460                choices,
 9461                selection,
 9462                buffer,
 9463                snippet_sort_order,
 9464            ),
 9465        ));
 9466    }
 9467
 9468    pub fn insert_snippet(
 9469        &mut self,
 9470        insertion_ranges: &[Range<usize>],
 9471        snippet: Snippet,
 9472        window: &mut Window,
 9473        cx: &mut Context<Self>,
 9474    ) -> Result<()> {
 9475        struct Tabstop<T> {
 9476            is_end_tabstop: bool,
 9477            ranges: Vec<Range<T>>,
 9478            choices: Option<Vec<String>>,
 9479        }
 9480
 9481        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9482            let snippet_text: Arc<str> = snippet.text.clone().into();
 9483            let edits = insertion_ranges
 9484                .iter()
 9485                .cloned()
 9486                .map(|range| (range, snippet_text.clone()));
 9487            let autoindent_mode = AutoindentMode::Block {
 9488                original_indent_columns: Vec::new(),
 9489            };
 9490            buffer.edit(edits, Some(autoindent_mode), cx);
 9491
 9492            let snapshot = &*buffer.read(cx);
 9493            let snippet = &snippet;
 9494            snippet
 9495                .tabstops
 9496                .iter()
 9497                .map(|tabstop| {
 9498                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9499                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9500                    });
 9501                    let mut tabstop_ranges = tabstop
 9502                        .ranges
 9503                        .iter()
 9504                        .flat_map(|tabstop_range| {
 9505                            let mut delta = 0_isize;
 9506                            insertion_ranges.iter().map(move |insertion_range| {
 9507                                let insertion_start = insertion_range.start as isize + delta;
 9508                                delta +=
 9509                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9510
 9511                                let start = ((insertion_start + tabstop_range.start) as usize)
 9512                                    .min(snapshot.len());
 9513                                let end = ((insertion_start + tabstop_range.end) as usize)
 9514                                    .min(snapshot.len());
 9515                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9516                            })
 9517                        })
 9518                        .collect::<Vec<_>>();
 9519                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9520
 9521                    Tabstop {
 9522                        is_end_tabstop,
 9523                        ranges: tabstop_ranges,
 9524                        choices: tabstop.choices.clone(),
 9525                    }
 9526                })
 9527                .collect::<Vec<_>>()
 9528        });
 9529        if let Some(tabstop) = tabstops.first() {
 9530            self.change_selections(Default::default(), window, cx, |s| {
 9531                // Reverse order so that the first range is the newest created selection.
 9532                // Completions will use it and autoscroll will prioritize it.
 9533                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9534            });
 9535
 9536            if let Some(choices) = &tabstop.choices {
 9537                if let Some(selection) = tabstop.ranges.first() {
 9538                    self.show_snippet_choices(choices, selection.clone(), cx)
 9539                }
 9540            }
 9541
 9542            // If we're already at the last tabstop and it's at the end of the snippet,
 9543            // we're done, we don't need to keep the state around.
 9544            if !tabstop.is_end_tabstop {
 9545                let choices = tabstops
 9546                    .iter()
 9547                    .map(|tabstop| tabstop.choices.clone())
 9548                    .collect();
 9549
 9550                let ranges = tabstops
 9551                    .into_iter()
 9552                    .map(|tabstop| tabstop.ranges)
 9553                    .collect::<Vec<_>>();
 9554
 9555                self.snippet_stack.push(SnippetState {
 9556                    active_index: 0,
 9557                    ranges,
 9558                    choices,
 9559                });
 9560            }
 9561
 9562            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9563            if self.autoclose_regions.is_empty() {
 9564                let snapshot = self.buffer.read(cx).snapshot(cx);
 9565                for selection in &mut self.selections.all::<Point>(cx) {
 9566                    let selection_head = selection.head();
 9567                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9568                        continue;
 9569                    };
 9570
 9571                    let mut bracket_pair = None;
 9572                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9573                    let prev_chars = snapshot
 9574                        .reversed_chars_at(selection_head)
 9575                        .collect::<String>();
 9576                    for (pair, enabled) in scope.brackets() {
 9577                        if enabled
 9578                            && pair.close
 9579                            && prev_chars.starts_with(pair.start.as_str())
 9580                            && next_chars.starts_with(pair.end.as_str())
 9581                        {
 9582                            bracket_pair = Some(pair.clone());
 9583                            break;
 9584                        }
 9585                    }
 9586                    if let Some(pair) = bracket_pair {
 9587                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9588                        let autoclose_enabled =
 9589                            self.use_autoclose && snapshot_settings.use_autoclose;
 9590                        if autoclose_enabled {
 9591                            let start = snapshot.anchor_after(selection_head);
 9592                            let end = snapshot.anchor_after(selection_head);
 9593                            self.autoclose_regions.push(AutocloseRegion {
 9594                                selection_id: selection.id,
 9595                                range: start..end,
 9596                                pair,
 9597                            });
 9598                        }
 9599                    }
 9600                }
 9601            }
 9602        }
 9603        Ok(())
 9604    }
 9605
 9606    pub fn move_to_next_snippet_tabstop(
 9607        &mut self,
 9608        window: &mut Window,
 9609        cx: &mut Context<Self>,
 9610    ) -> bool {
 9611        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9612    }
 9613
 9614    pub fn move_to_prev_snippet_tabstop(
 9615        &mut self,
 9616        window: &mut Window,
 9617        cx: &mut Context<Self>,
 9618    ) -> bool {
 9619        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9620    }
 9621
 9622    pub fn move_to_snippet_tabstop(
 9623        &mut self,
 9624        bias: Bias,
 9625        window: &mut Window,
 9626        cx: &mut Context<Self>,
 9627    ) -> bool {
 9628        if let Some(mut snippet) = self.snippet_stack.pop() {
 9629            match bias {
 9630                Bias::Left => {
 9631                    if snippet.active_index > 0 {
 9632                        snippet.active_index -= 1;
 9633                    } else {
 9634                        self.snippet_stack.push(snippet);
 9635                        return false;
 9636                    }
 9637                }
 9638                Bias::Right => {
 9639                    if snippet.active_index + 1 < snippet.ranges.len() {
 9640                        snippet.active_index += 1;
 9641                    } else {
 9642                        self.snippet_stack.push(snippet);
 9643                        return false;
 9644                    }
 9645                }
 9646            }
 9647            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9648                self.change_selections(Default::default(), window, cx, |s| {
 9649                    // Reverse order so that the first range is the newest created selection.
 9650                    // Completions will use it and autoscroll will prioritize it.
 9651                    s.select_ranges(current_ranges.iter().rev().cloned())
 9652                });
 9653
 9654                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9655                    if let Some(selection) = current_ranges.first() {
 9656                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9657                    }
 9658                }
 9659
 9660                // If snippet state is not at the last tabstop, push it back on the stack
 9661                if snippet.active_index + 1 < snippet.ranges.len() {
 9662                    self.snippet_stack.push(snippet);
 9663                }
 9664                return true;
 9665            }
 9666        }
 9667
 9668        false
 9669    }
 9670
 9671    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9672        self.transact(window, cx, |this, window, cx| {
 9673            this.select_all(&SelectAll, window, cx);
 9674            this.insert("", window, cx);
 9675        });
 9676    }
 9677
 9678    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9680        self.transact(window, cx, |this, window, cx| {
 9681            this.select_autoclose_pair(window, cx);
 9682            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9683            if !this.linked_edit_ranges.is_empty() {
 9684                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9685                let snapshot = this.buffer.read(cx).snapshot(cx);
 9686
 9687                for selection in selections.iter() {
 9688                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9689                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9690                    if selection_start.buffer_id != selection_end.buffer_id {
 9691                        continue;
 9692                    }
 9693                    if let Some(ranges) =
 9694                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9695                    {
 9696                        for (buffer, entries) in ranges {
 9697                            linked_ranges.entry(buffer).or_default().extend(entries);
 9698                        }
 9699                    }
 9700                }
 9701            }
 9702
 9703            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9704            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9705            for selection in &mut selections {
 9706                if selection.is_empty() {
 9707                    let old_head = selection.head();
 9708                    let mut new_head =
 9709                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9710                            .to_point(&display_map);
 9711                    if let Some((buffer, line_buffer_range)) = display_map
 9712                        .buffer_snapshot
 9713                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9714                    {
 9715                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9716                        let indent_len = match indent_size.kind {
 9717                            IndentKind::Space => {
 9718                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9719                            }
 9720                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9721                        };
 9722                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9723                            let indent_len = indent_len.get();
 9724                            new_head = cmp::min(
 9725                                new_head,
 9726                                MultiBufferPoint::new(
 9727                                    old_head.row,
 9728                                    ((old_head.column - 1) / indent_len) * indent_len,
 9729                                ),
 9730                            );
 9731                        }
 9732                    }
 9733
 9734                    selection.set_head(new_head, SelectionGoal::None);
 9735                }
 9736            }
 9737
 9738            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9739            this.insert("", window, cx);
 9740            let empty_str: Arc<str> = Arc::from("");
 9741            for (buffer, edits) in linked_ranges {
 9742                let snapshot = buffer.read(cx).snapshot();
 9743                use text::ToPoint as TP;
 9744
 9745                let edits = edits
 9746                    .into_iter()
 9747                    .map(|range| {
 9748                        let end_point = TP::to_point(&range.end, &snapshot);
 9749                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9750
 9751                        if end_point == start_point {
 9752                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9753                                .saturating_sub(1);
 9754                            start_point =
 9755                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9756                        };
 9757
 9758                        (start_point..end_point, empty_str.clone())
 9759                    })
 9760                    .sorted_by_key(|(range, _)| range.start)
 9761                    .collect::<Vec<_>>();
 9762                buffer.update(cx, |this, cx| {
 9763                    this.edit(edits, None, cx);
 9764                })
 9765            }
 9766            this.refresh_inline_completion(true, false, window, cx);
 9767            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9768        });
 9769    }
 9770
 9771    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9773        self.transact(window, cx, |this, window, cx| {
 9774            this.change_selections(Default::default(), window, cx, |s| {
 9775                s.move_with(|map, selection| {
 9776                    if selection.is_empty() {
 9777                        let cursor = movement::right(map, selection.head());
 9778                        selection.end = cursor;
 9779                        selection.reversed = true;
 9780                        selection.goal = SelectionGoal::None;
 9781                    }
 9782                })
 9783            });
 9784            this.insert("", window, cx);
 9785            this.refresh_inline_completion(true, false, window, cx);
 9786        });
 9787    }
 9788
 9789    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9790        if self.mode.is_single_line() {
 9791            cx.propagate();
 9792            return;
 9793        }
 9794
 9795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9796        if self.move_to_prev_snippet_tabstop(window, cx) {
 9797            return;
 9798        }
 9799        self.outdent(&Outdent, window, cx);
 9800    }
 9801
 9802    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9803        if self.mode.is_single_line() {
 9804            cx.propagate();
 9805            return;
 9806        }
 9807
 9808        if self.move_to_next_snippet_tabstop(window, cx) {
 9809            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9810            return;
 9811        }
 9812        if self.read_only(cx) {
 9813            return;
 9814        }
 9815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9816        let mut selections = self.selections.all_adjusted(cx);
 9817        let buffer = self.buffer.read(cx);
 9818        let snapshot = buffer.snapshot(cx);
 9819        let rows_iter = selections.iter().map(|s| s.head().row);
 9820        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9821
 9822        let has_some_cursor_in_whitespace = selections
 9823            .iter()
 9824            .filter(|selection| selection.is_empty())
 9825            .any(|selection| {
 9826                let cursor = selection.head();
 9827                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9828                cursor.column < current_indent.len
 9829            });
 9830
 9831        let mut edits = Vec::new();
 9832        let mut prev_edited_row = 0;
 9833        let mut row_delta = 0;
 9834        for selection in &mut selections {
 9835            if selection.start.row != prev_edited_row {
 9836                row_delta = 0;
 9837            }
 9838            prev_edited_row = selection.end.row;
 9839
 9840            // If the selection is non-empty, then increase the indentation of the selected lines.
 9841            if !selection.is_empty() {
 9842                row_delta =
 9843                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9844                continue;
 9845            }
 9846
 9847            let cursor = selection.head();
 9848            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9849            if let Some(suggested_indent) =
 9850                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9851            {
 9852                // Don't do anything if already at suggested indent
 9853                // and there is any other cursor which is not
 9854                if has_some_cursor_in_whitespace
 9855                    && cursor.column == current_indent.len
 9856                    && current_indent.len == suggested_indent.len
 9857                {
 9858                    continue;
 9859                }
 9860
 9861                // Adjust line and move cursor to suggested indent
 9862                // if cursor is not at suggested indent
 9863                if cursor.column < suggested_indent.len
 9864                    && cursor.column <= current_indent.len
 9865                    && current_indent.len <= suggested_indent.len
 9866                {
 9867                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9868                    selection.end = selection.start;
 9869                    if row_delta == 0 {
 9870                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9871                            cursor.row,
 9872                            current_indent,
 9873                            suggested_indent,
 9874                        ));
 9875                        row_delta = suggested_indent.len - current_indent.len;
 9876                    }
 9877                    continue;
 9878                }
 9879
 9880                // If current indent is more than suggested indent
 9881                // only move cursor to current indent and skip indent
 9882                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9883                    selection.start = Point::new(cursor.row, current_indent.len);
 9884                    selection.end = selection.start;
 9885                    continue;
 9886                }
 9887            }
 9888
 9889            // Otherwise, insert a hard or soft tab.
 9890            let settings = buffer.language_settings_at(cursor, cx);
 9891            let tab_size = if settings.hard_tabs {
 9892                IndentSize::tab()
 9893            } else {
 9894                let tab_size = settings.tab_size.get();
 9895                let indent_remainder = snapshot
 9896                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9897                    .flat_map(str::chars)
 9898                    .fold(row_delta % tab_size, |counter: u32, c| {
 9899                        if c == '\t' {
 9900                            0
 9901                        } else {
 9902                            (counter + 1) % tab_size
 9903                        }
 9904                    });
 9905
 9906                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9907                IndentSize::spaces(chars_to_next_tab_stop)
 9908            };
 9909            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9910            selection.end = selection.start;
 9911            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9912            row_delta += tab_size.len;
 9913        }
 9914
 9915        self.transact(window, cx, |this, window, cx| {
 9916            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9917            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9918            this.refresh_inline_completion(true, false, window, cx);
 9919        });
 9920    }
 9921
 9922    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9923        if self.read_only(cx) {
 9924            return;
 9925        }
 9926        if self.mode.is_single_line() {
 9927            cx.propagate();
 9928            return;
 9929        }
 9930
 9931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9932        let mut selections = self.selections.all::<Point>(cx);
 9933        let mut prev_edited_row = 0;
 9934        let mut row_delta = 0;
 9935        let mut edits = Vec::new();
 9936        let buffer = self.buffer.read(cx);
 9937        let snapshot = buffer.snapshot(cx);
 9938        for selection in &mut selections {
 9939            if selection.start.row != prev_edited_row {
 9940                row_delta = 0;
 9941            }
 9942            prev_edited_row = selection.end.row;
 9943
 9944            row_delta =
 9945                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9946        }
 9947
 9948        self.transact(window, cx, |this, window, cx| {
 9949            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9950            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9951        });
 9952    }
 9953
 9954    fn indent_selection(
 9955        buffer: &MultiBuffer,
 9956        snapshot: &MultiBufferSnapshot,
 9957        selection: &mut Selection<Point>,
 9958        edits: &mut Vec<(Range<Point>, String)>,
 9959        delta_for_start_row: u32,
 9960        cx: &App,
 9961    ) -> u32 {
 9962        let settings = buffer.language_settings_at(selection.start, cx);
 9963        let tab_size = settings.tab_size.get();
 9964        let indent_kind = if settings.hard_tabs {
 9965            IndentKind::Tab
 9966        } else {
 9967            IndentKind::Space
 9968        };
 9969        let mut start_row = selection.start.row;
 9970        let mut end_row = selection.end.row + 1;
 9971
 9972        // If a selection ends at the beginning of a line, don't indent
 9973        // that last line.
 9974        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9975            end_row -= 1;
 9976        }
 9977
 9978        // Avoid re-indenting a row that has already been indented by a
 9979        // previous selection, but still update this selection's column
 9980        // to reflect that indentation.
 9981        if delta_for_start_row > 0 {
 9982            start_row += 1;
 9983            selection.start.column += delta_for_start_row;
 9984            if selection.end.row == selection.start.row {
 9985                selection.end.column += delta_for_start_row;
 9986            }
 9987        }
 9988
 9989        let mut delta_for_end_row = 0;
 9990        let has_multiple_rows = start_row + 1 != end_row;
 9991        for row in start_row..end_row {
 9992            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9993            let indent_delta = match (current_indent.kind, indent_kind) {
 9994                (IndentKind::Space, IndentKind::Space) => {
 9995                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9996                    IndentSize::spaces(columns_to_next_tab_stop)
 9997                }
 9998                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9999                (_, IndentKind::Tab) => IndentSize::tab(),
10000            };
10001
10002            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10003                0
10004            } else {
10005                selection.start.column
10006            };
10007            let row_start = Point::new(row, start);
10008            edits.push((
10009                row_start..row_start,
10010                indent_delta.chars().collect::<String>(),
10011            ));
10012
10013            // Update this selection's endpoints to reflect the indentation.
10014            if row == selection.start.row {
10015                selection.start.column += indent_delta.len;
10016            }
10017            if row == selection.end.row {
10018                selection.end.column += indent_delta.len;
10019                delta_for_end_row = indent_delta.len;
10020            }
10021        }
10022
10023        if selection.start.row == selection.end.row {
10024            delta_for_start_row + delta_for_end_row
10025        } else {
10026            delta_for_end_row
10027        }
10028    }
10029
10030    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10031        if self.read_only(cx) {
10032            return;
10033        }
10034        if self.mode.is_single_line() {
10035            cx.propagate();
10036            return;
10037        }
10038
10039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10040        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10041        let selections = self.selections.all::<Point>(cx);
10042        let mut deletion_ranges = Vec::new();
10043        let mut last_outdent = None;
10044        {
10045            let buffer = self.buffer.read(cx);
10046            let snapshot = buffer.snapshot(cx);
10047            for selection in &selections {
10048                let settings = buffer.language_settings_at(selection.start, cx);
10049                let tab_size = settings.tab_size.get();
10050                let mut rows = selection.spanned_rows(false, &display_map);
10051
10052                // Avoid re-outdenting a row that has already been outdented by a
10053                // previous selection.
10054                if let Some(last_row) = last_outdent {
10055                    if last_row == rows.start {
10056                        rows.start = rows.start.next_row();
10057                    }
10058                }
10059                let has_multiple_rows = rows.len() > 1;
10060                for row in rows.iter_rows() {
10061                    let indent_size = snapshot.indent_size_for_line(row);
10062                    if indent_size.len > 0 {
10063                        let deletion_len = match indent_size.kind {
10064                            IndentKind::Space => {
10065                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10066                                if columns_to_prev_tab_stop == 0 {
10067                                    tab_size
10068                                } else {
10069                                    columns_to_prev_tab_stop
10070                                }
10071                            }
10072                            IndentKind::Tab => 1,
10073                        };
10074                        let start = if has_multiple_rows
10075                            || deletion_len > selection.start.column
10076                            || indent_size.len < selection.start.column
10077                        {
10078                            0
10079                        } else {
10080                            selection.start.column - deletion_len
10081                        };
10082                        deletion_ranges.push(
10083                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10084                        );
10085                        last_outdent = Some(row);
10086                    }
10087                }
10088            }
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |buffer, cx| {
10093                let empty_str: Arc<str> = Arc::default();
10094                buffer.edit(
10095                    deletion_ranges
10096                        .into_iter()
10097                        .map(|range| (range, empty_str.clone())),
10098                    None,
10099                    cx,
10100                );
10101            });
10102            let selections = this.selections.all::<usize>(cx);
10103            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10104        });
10105    }
10106
10107    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10108        if self.read_only(cx) {
10109            return;
10110        }
10111        if self.mode.is_single_line() {
10112            cx.propagate();
10113            return;
10114        }
10115
10116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10117        let selections = self
10118            .selections
10119            .all::<usize>(cx)
10120            .into_iter()
10121            .map(|s| s.range());
10122
10123        self.transact(window, cx, |this, window, cx| {
10124            this.buffer.update(cx, |buffer, cx| {
10125                buffer.autoindent_ranges(selections, cx);
10126            });
10127            let selections = this.selections.all::<usize>(cx);
10128            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10129        });
10130    }
10131
10132    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10135        let selections = self.selections.all::<Point>(cx);
10136
10137        let mut new_cursors = Vec::new();
10138        let mut edit_ranges = Vec::new();
10139        let mut selections = selections.iter().peekable();
10140        while let Some(selection) = selections.next() {
10141            let mut rows = selection.spanned_rows(false, &display_map);
10142            let goal_display_column = selection.head().to_display_point(&display_map).column();
10143
10144            // Accumulate contiguous regions of rows that we want to delete.
10145            while let Some(next_selection) = selections.peek() {
10146                let next_rows = next_selection.spanned_rows(false, &display_map);
10147                if next_rows.start <= rows.end {
10148                    rows.end = next_rows.end;
10149                    selections.next().unwrap();
10150                } else {
10151                    break;
10152                }
10153            }
10154
10155            let buffer = &display_map.buffer_snapshot;
10156            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10157            let edit_end;
10158            let cursor_buffer_row;
10159            if buffer.max_point().row >= rows.end.0 {
10160                // If there's a line after the range, delete the \n from the end of the row range
10161                // and position the cursor on the next line.
10162                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10163                cursor_buffer_row = rows.end;
10164            } else {
10165                // If there isn't a line after the range, delete the \n from the line before the
10166                // start of the row range and position the cursor there.
10167                edit_start = edit_start.saturating_sub(1);
10168                edit_end = buffer.len();
10169                cursor_buffer_row = rows.start.previous_row();
10170            }
10171
10172            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10173            *cursor.column_mut() =
10174                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10175
10176            new_cursors.push((
10177                selection.id,
10178                buffer.anchor_after(cursor.to_point(&display_map)),
10179            ));
10180            edit_ranges.push(edit_start..edit_end);
10181        }
10182
10183        self.transact(window, cx, |this, window, cx| {
10184            let buffer = this.buffer.update(cx, |buffer, cx| {
10185                let empty_str: Arc<str> = Arc::default();
10186                buffer.edit(
10187                    edit_ranges
10188                        .into_iter()
10189                        .map(|range| (range, empty_str.clone())),
10190                    None,
10191                    cx,
10192                );
10193                buffer.snapshot(cx)
10194            });
10195            let new_selections = new_cursors
10196                .into_iter()
10197                .map(|(id, cursor)| {
10198                    let cursor = cursor.to_point(&buffer);
10199                    Selection {
10200                        id,
10201                        start: cursor,
10202                        end: cursor,
10203                        reversed: false,
10204                        goal: SelectionGoal::None,
10205                    }
10206                })
10207                .collect();
10208
10209            this.change_selections(Default::default(), window, cx, |s| {
10210                s.select(new_selections);
10211            });
10212        });
10213    }
10214
10215    pub fn join_lines_impl(
10216        &mut self,
10217        insert_whitespace: bool,
10218        window: &mut Window,
10219        cx: &mut Context<Self>,
10220    ) {
10221        if self.read_only(cx) {
10222            return;
10223        }
10224        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10225        for selection in self.selections.all::<Point>(cx) {
10226            let start = MultiBufferRow(selection.start.row);
10227            // Treat single line selections as if they include the next line. Otherwise this action
10228            // would do nothing for single line selections individual cursors.
10229            let end = if selection.start.row == selection.end.row {
10230                MultiBufferRow(selection.start.row + 1)
10231            } else {
10232                MultiBufferRow(selection.end.row)
10233            };
10234
10235            if let Some(last_row_range) = row_ranges.last_mut() {
10236                if start <= last_row_range.end {
10237                    last_row_range.end = end;
10238                    continue;
10239                }
10240            }
10241            row_ranges.push(start..end);
10242        }
10243
10244        let snapshot = self.buffer.read(cx).snapshot(cx);
10245        let mut cursor_positions = Vec::new();
10246        for row_range in &row_ranges {
10247            let anchor = snapshot.anchor_before(Point::new(
10248                row_range.end.previous_row().0,
10249                snapshot.line_len(row_range.end.previous_row()),
10250            ));
10251            cursor_positions.push(anchor..anchor);
10252        }
10253
10254        self.transact(window, cx, |this, window, cx| {
10255            for row_range in row_ranges.into_iter().rev() {
10256                for row in row_range.iter_rows().rev() {
10257                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10258                    let next_line_row = row.next_row();
10259                    let indent = snapshot.indent_size_for_line(next_line_row);
10260                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10261
10262                    let replace =
10263                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10264                            " "
10265                        } else {
10266                            ""
10267                        };
10268
10269                    this.buffer.update(cx, |buffer, cx| {
10270                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10271                    });
10272                }
10273            }
10274
10275            this.change_selections(Default::default(), window, cx, |s| {
10276                s.select_anchor_ranges(cursor_positions)
10277            });
10278        });
10279    }
10280
10281    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10283        self.join_lines_impl(true, window, cx);
10284    }
10285
10286    pub fn sort_lines_case_sensitive(
10287        &mut self,
10288        _: &SortLinesCaseSensitive,
10289        window: &mut Window,
10290        cx: &mut Context<Self>,
10291    ) {
10292        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10293    }
10294
10295    pub fn sort_lines_by_length(
10296        &mut self,
10297        _: &SortLinesByLength,
10298        window: &mut Window,
10299        cx: &mut Context<Self>,
10300    ) {
10301        self.manipulate_immutable_lines(window, cx, |lines| {
10302            lines.sort_by_key(|&line| line.chars().count())
10303        })
10304    }
10305
10306    pub fn sort_lines_case_insensitive(
10307        &mut self,
10308        _: &SortLinesCaseInsensitive,
10309        window: &mut Window,
10310        cx: &mut Context<Self>,
10311    ) {
10312        self.manipulate_immutable_lines(window, cx, |lines| {
10313            lines.sort_by_key(|line| line.to_lowercase())
10314        })
10315    }
10316
10317    pub fn unique_lines_case_insensitive(
10318        &mut self,
10319        _: &UniqueLinesCaseInsensitive,
10320        window: &mut Window,
10321        cx: &mut Context<Self>,
10322    ) {
10323        self.manipulate_immutable_lines(window, cx, |lines| {
10324            let mut seen = HashSet::default();
10325            lines.retain(|line| seen.insert(line.to_lowercase()));
10326        })
10327    }
10328
10329    pub fn unique_lines_case_sensitive(
10330        &mut self,
10331        _: &UniqueLinesCaseSensitive,
10332        window: &mut Window,
10333        cx: &mut Context<Self>,
10334    ) {
10335        self.manipulate_immutable_lines(window, cx, |lines| {
10336            let mut seen = HashSet::default();
10337            lines.retain(|line| seen.insert(*line));
10338        })
10339    }
10340
10341    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10342        let Some(project) = self.project.clone() else {
10343            return;
10344        };
10345        self.reload(project, window, cx)
10346            .detach_and_notify_err(window, cx);
10347    }
10348
10349    pub fn restore_file(
10350        &mut self,
10351        _: &::git::RestoreFile,
10352        window: &mut Window,
10353        cx: &mut Context<Self>,
10354    ) {
10355        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10356        let mut buffer_ids = HashSet::default();
10357        let snapshot = self.buffer().read(cx).snapshot(cx);
10358        for selection in self.selections.all::<usize>(cx) {
10359            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10360        }
10361
10362        let buffer = self.buffer().read(cx);
10363        let ranges = buffer_ids
10364            .into_iter()
10365            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10366            .collect::<Vec<_>>();
10367
10368        self.restore_hunks_in_ranges(ranges, window, cx);
10369    }
10370
10371    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10372        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10373        let selections = self
10374            .selections
10375            .all(cx)
10376            .into_iter()
10377            .map(|s| s.range())
10378            .collect();
10379        self.restore_hunks_in_ranges(selections, window, cx);
10380    }
10381
10382    pub fn restore_hunks_in_ranges(
10383        &mut self,
10384        ranges: Vec<Range<Point>>,
10385        window: &mut Window,
10386        cx: &mut Context<Editor>,
10387    ) {
10388        let mut revert_changes = HashMap::default();
10389        let chunk_by = self
10390            .snapshot(window, cx)
10391            .hunks_for_ranges(ranges)
10392            .into_iter()
10393            .chunk_by(|hunk| hunk.buffer_id);
10394        for (buffer_id, hunks) in &chunk_by {
10395            let hunks = hunks.collect::<Vec<_>>();
10396            for hunk in &hunks {
10397                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10398            }
10399            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10400        }
10401        drop(chunk_by);
10402        if !revert_changes.is_empty() {
10403            self.transact(window, cx, |editor, window, cx| {
10404                editor.restore(revert_changes, window, cx);
10405            });
10406        }
10407    }
10408
10409    pub fn open_active_item_in_terminal(
10410        &mut self,
10411        _: &OpenInTerminal,
10412        window: &mut Window,
10413        cx: &mut Context<Self>,
10414    ) {
10415        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10416            let project_path = buffer.read(cx).project_path(cx)?;
10417            let project = self.project.as_ref()?.read(cx);
10418            let entry = project.entry_for_path(&project_path, cx)?;
10419            let parent = match &entry.canonical_path {
10420                Some(canonical_path) => canonical_path.to_path_buf(),
10421                None => project.absolute_path(&project_path, cx)?,
10422            }
10423            .parent()?
10424            .to_path_buf();
10425            Some(parent)
10426        }) {
10427            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10428        }
10429    }
10430
10431    fn set_breakpoint_context_menu(
10432        &mut self,
10433        display_row: DisplayRow,
10434        position: Option<Anchor>,
10435        clicked_point: gpui::Point<Pixels>,
10436        window: &mut Window,
10437        cx: &mut Context<Self>,
10438    ) {
10439        let source = self
10440            .buffer
10441            .read(cx)
10442            .snapshot(cx)
10443            .anchor_before(Point::new(display_row.0, 0u32));
10444
10445        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10446
10447        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10448            self,
10449            source,
10450            clicked_point,
10451            context_menu,
10452            window,
10453            cx,
10454        );
10455    }
10456
10457    fn add_edit_breakpoint_block(
10458        &mut self,
10459        anchor: Anchor,
10460        breakpoint: &Breakpoint,
10461        edit_action: BreakpointPromptEditAction,
10462        window: &mut Window,
10463        cx: &mut Context<Self>,
10464    ) {
10465        let weak_editor = cx.weak_entity();
10466        let bp_prompt = cx.new(|cx| {
10467            BreakpointPromptEditor::new(
10468                weak_editor,
10469                anchor,
10470                breakpoint.clone(),
10471                edit_action,
10472                window,
10473                cx,
10474            )
10475        });
10476
10477        let height = bp_prompt.update(cx, |this, cx| {
10478            this.prompt
10479                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10480        });
10481        let cloned_prompt = bp_prompt.clone();
10482        let blocks = vec![BlockProperties {
10483            style: BlockStyle::Sticky,
10484            placement: BlockPlacement::Above(anchor),
10485            height: Some(height),
10486            render: Arc::new(move |cx| {
10487                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10488                cloned_prompt.clone().into_any_element()
10489            }),
10490            priority: 0,
10491        }];
10492
10493        let focus_handle = bp_prompt.focus_handle(cx);
10494        window.focus(&focus_handle);
10495
10496        let block_ids = self.insert_blocks(blocks, None, cx);
10497        bp_prompt.update(cx, |prompt, _| {
10498            prompt.add_block_ids(block_ids);
10499        });
10500    }
10501
10502    pub(crate) fn breakpoint_at_row(
10503        &self,
10504        row: u32,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) -> Option<(Anchor, Breakpoint)> {
10508        let snapshot = self.snapshot(window, cx);
10509        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10510
10511        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10512    }
10513
10514    pub(crate) fn breakpoint_at_anchor(
10515        &self,
10516        breakpoint_position: Anchor,
10517        snapshot: &EditorSnapshot,
10518        cx: &mut Context<Self>,
10519    ) -> Option<(Anchor, Breakpoint)> {
10520        let project = self.project.clone()?;
10521
10522        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10523            snapshot
10524                .buffer_snapshot
10525                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10526        })?;
10527
10528        let enclosing_excerpt = breakpoint_position.excerpt_id;
10529        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10530        let buffer_snapshot = buffer.read(cx).snapshot();
10531
10532        let row = buffer_snapshot
10533            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10534            .row;
10535
10536        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10537        let anchor_end = snapshot
10538            .buffer_snapshot
10539            .anchor_after(Point::new(row, line_len));
10540
10541        let bp = self
10542            .breakpoint_store
10543            .as_ref()?
10544            .read_with(cx, |breakpoint_store, cx| {
10545                breakpoint_store
10546                    .breakpoints(
10547                        &buffer,
10548                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10549                        &buffer_snapshot,
10550                        cx,
10551                    )
10552                    .next()
10553                    .and_then(|(bp, _)| {
10554                        let breakpoint_row = buffer_snapshot
10555                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10556                            .row;
10557
10558                        if breakpoint_row == row {
10559                            snapshot
10560                                .buffer_snapshot
10561                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10562                                .map(|position| (position, bp.bp.clone()))
10563                        } else {
10564                            None
10565                        }
10566                    })
10567            });
10568        bp
10569    }
10570
10571    pub fn edit_log_breakpoint(
10572        &mut self,
10573        _: &EditLogBreakpoint,
10574        window: &mut Window,
10575        cx: &mut Context<Self>,
10576    ) {
10577        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10578            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10579                message: None,
10580                state: BreakpointState::Enabled,
10581                condition: None,
10582                hit_condition: None,
10583            });
10584
10585            self.add_edit_breakpoint_block(
10586                anchor,
10587                &breakpoint,
10588                BreakpointPromptEditAction::Log,
10589                window,
10590                cx,
10591            );
10592        }
10593    }
10594
10595    fn breakpoints_at_cursors(
10596        &self,
10597        window: &mut Window,
10598        cx: &mut Context<Self>,
10599    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10600        let snapshot = self.snapshot(window, cx);
10601        let cursors = self
10602            .selections
10603            .disjoint_anchors()
10604            .into_iter()
10605            .map(|selection| {
10606                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10607
10608                let breakpoint_position = self
10609                    .breakpoint_at_row(cursor_position.row, window, cx)
10610                    .map(|bp| bp.0)
10611                    .unwrap_or_else(|| {
10612                        snapshot
10613                            .display_snapshot
10614                            .buffer_snapshot
10615                            .anchor_after(Point::new(cursor_position.row, 0))
10616                    });
10617
10618                let breakpoint = self
10619                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10620                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10621
10622                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10623            })
10624            // 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.
10625            .collect::<HashMap<Anchor, _>>();
10626
10627        cursors.into_iter().collect()
10628    }
10629
10630    pub fn enable_breakpoint(
10631        &mut self,
10632        _: &crate::actions::EnableBreakpoint,
10633        window: &mut Window,
10634        cx: &mut Context<Self>,
10635    ) {
10636        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10637            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10638                continue;
10639            };
10640            self.edit_breakpoint_at_anchor(
10641                anchor,
10642                breakpoint,
10643                BreakpointEditAction::InvertState,
10644                cx,
10645            );
10646        }
10647    }
10648
10649    pub fn disable_breakpoint(
10650        &mut self,
10651        _: &crate::actions::DisableBreakpoint,
10652        window: &mut Window,
10653        cx: &mut Context<Self>,
10654    ) {
10655        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10656            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10657                continue;
10658            };
10659            self.edit_breakpoint_at_anchor(
10660                anchor,
10661                breakpoint,
10662                BreakpointEditAction::InvertState,
10663                cx,
10664            );
10665        }
10666    }
10667
10668    pub fn toggle_breakpoint(
10669        &mut self,
10670        _: &crate::actions::ToggleBreakpoint,
10671        window: &mut Window,
10672        cx: &mut Context<Self>,
10673    ) {
10674        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10675            if let Some(breakpoint) = breakpoint {
10676                self.edit_breakpoint_at_anchor(
10677                    anchor,
10678                    breakpoint,
10679                    BreakpointEditAction::Toggle,
10680                    cx,
10681                );
10682            } else {
10683                self.edit_breakpoint_at_anchor(
10684                    anchor,
10685                    Breakpoint::new_standard(),
10686                    BreakpointEditAction::Toggle,
10687                    cx,
10688                );
10689            }
10690        }
10691    }
10692
10693    pub fn edit_breakpoint_at_anchor(
10694        &mut self,
10695        breakpoint_position: Anchor,
10696        breakpoint: Breakpoint,
10697        edit_action: BreakpointEditAction,
10698        cx: &mut Context<Self>,
10699    ) {
10700        let Some(breakpoint_store) = &self.breakpoint_store else {
10701            return;
10702        };
10703
10704        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10705            if breakpoint_position == Anchor::min() {
10706                self.buffer()
10707                    .read(cx)
10708                    .excerpt_buffer_ids()
10709                    .into_iter()
10710                    .next()
10711            } else {
10712                None
10713            }
10714        }) else {
10715            return;
10716        };
10717
10718        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10719            return;
10720        };
10721
10722        breakpoint_store.update(cx, |breakpoint_store, cx| {
10723            breakpoint_store.toggle_breakpoint(
10724                buffer,
10725                BreakpointWithPosition {
10726                    position: breakpoint_position.text_anchor,
10727                    bp: breakpoint,
10728                },
10729                edit_action,
10730                cx,
10731            );
10732        });
10733
10734        cx.notify();
10735    }
10736
10737    #[cfg(any(test, feature = "test-support"))]
10738    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10739        self.breakpoint_store.clone()
10740    }
10741
10742    pub fn prepare_restore_change(
10743        &self,
10744        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10745        hunk: &MultiBufferDiffHunk,
10746        cx: &mut App,
10747    ) -> Option<()> {
10748        if hunk.is_created_file() {
10749            return None;
10750        }
10751        let buffer = self.buffer.read(cx);
10752        let diff = buffer.diff_for(hunk.buffer_id)?;
10753        let buffer = buffer.buffer(hunk.buffer_id)?;
10754        let buffer = buffer.read(cx);
10755        let original_text = diff
10756            .read(cx)
10757            .base_text()
10758            .as_rope()
10759            .slice(hunk.diff_base_byte_range.clone());
10760        let buffer_snapshot = buffer.snapshot();
10761        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10762        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10763            probe
10764                .0
10765                .start
10766                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10767                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10768        }) {
10769            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10770            Some(())
10771        } else {
10772            None
10773        }
10774    }
10775
10776    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10777        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10778    }
10779
10780    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10781        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10782    }
10783
10784    fn manipulate_lines<M>(
10785        &mut self,
10786        window: &mut Window,
10787        cx: &mut Context<Self>,
10788        mut manipulate: M,
10789    ) where
10790        M: FnMut(&str) -> LineManipulationResult,
10791    {
10792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10793
10794        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10795        let buffer = self.buffer.read(cx).snapshot(cx);
10796
10797        let mut edits = Vec::new();
10798
10799        let selections = self.selections.all::<Point>(cx);
10800        let mut selections = selections.iter().peekable();
10801        let mut contiguous_row_selections = Vec::new();
10802        let mut new_selections = Vec::new();
10803        let mut added_lines = 0;
10804        let mut removed_lines = 0;
10805
10806        while let Some(selection) = selections.next() {
10807            let (start_row, end_row) = consume_contiguous_rows(
10808                &mut contiguous_row_selections,
10809                selection,
10810                &display_map,
10811                &mut selections,
10812            );
10813
10814            let start_point = Point::new(start_row.0, 0);
10815            let end_point = Point::new(
10816                end_row.previous_row().0,
10817                buffer.line_len(end_row.previous_row()),
10818            );
10819            let text = buffer
10820                .text_for_range(start_point..end_point)
10821                .collect::<String>();
10822
10823            let LineManipulationResult {
10824                new_text,
10825                line_count_before,
10826                line_count_after,
10827            } = manipulate(&text);
10828
10829            edits.push((start_point..end_point, new_text));
10830
10831            // Selections must change based on added and removed line count
10832            let start_row =
10833                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10834            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10835            new_selections.push(Selection {
10836                id: selection.id,
10837                start: start_row,
10838                end: end_row,
10839                goal: SelectionGoal::None,
10840                reversed: selection.reversed,
10841            });
10842
10843            if line_count_after > line_count_before {
10844                added_lines += line_count_after - line_count_before;
10845            } else if line_count_before > line_count_after {
10846                removed_lines += line_count_before - line_count_after;
10847            }
10848        }
10849
10850        self.transact(window, cx, |this, window, cx| {
10851            let buffer = this.buffer.update(cx, |buffer, cx| {
10852                buffer.edit(edits, None, cx);
10853                buffer.snapshot(cx)
10854            });
10855
10856            // Recalculate offsets on newly edited buffer
10857            let new_selections = new_selections
10858                .iter()
10859                .map(|s| {
10860                    let start_point = Point::new(s.start.0, 0);
10861                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10862                    Selection {
10863                        id: s.id,
10864                        start: buffer.point_to_offset(start_point),
10865                        end: buffer.point_to_offset(end_point),
10866                        goal: s.goal,
10867                        reversed: s.reversed,
10868                    }
10869                })
10870                .collect();
10871
10872            this.change_selections(Default::default(), window, cx, |s| {
10873                s.select(new_selections);
10874            });
10875
10876            this.request_autoscroll(Autoscroll::fit(), cx);
10877        });
10878    }
10879
10880    fn manipulate_immutable_lines<Fn>(
10881        &mut self,
10882        window: &mut Window,
10883        cx: &mut Context<Self>,
10884        mut callback: Fn,
10885    ) where
10886        Fn: FnMut(&mut Vec<&str>),
10887    {
10888        self.manipulate_lines(window, cx, |text| {
10889            let mut lines: Vec<&str> = text.split('\n').collect();
10890            let line_count_before = lines.len();
10891
10892            callback(&mut lines);
10893
10894            LineManipulationResult {
10895                new_text: lines.join("\n"),
10896                line_count_before,
10897                line_count_after: lines.len(),
10898            }
10899        });
10900    }
10901
10902    fn manipulate_mutable_lines<Fn>(
10903        &mut self,
10904        window: &mut Window,
10905        cx: &mut Context<Self>,
10906        mut callback: Fn,
10907    ) where
10908        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10909    {
10910        self.manipulate_lines(window, cx, |text| {
10911            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10912            let line_count_before = lines.len();
10913
10914            callback(&mut lines);
10915
10916            LineManipulationResult {
10917                new_text: lines.join("\n"),
10918                line_count_before,
10919                line_count_after: lines.len(),
10920            }
10921        });
10922    }
10923
10924    pub fn convert_indentation_to_spaces(
10925        &mut self,
10926        _: &ConvertIndentationToSpaces,
10927        window: &mut Window,
10928        cx: &mut Context<Self>,
10929    ) {
10930        let settings = self.buffer.read(cx).language_settings(cx);
10931        let tab_size = settings.tab_size.get() as usize;
10932
10933        self.manipulate_mutable_lines(window, cx, |lines| {
10934            // Allocates a reasonably sized scratch buffer once for the whole loop
10935            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10936            // Avoids recomputing spaces that could be inserted many times
10937            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10938                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10939                .collect();
10940
10941            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10942                let mut chars = line.as_ref().chars();
10943                let mut col = 0;
10944                let mut changed = false;
10945
10946                while let Some(ch) = chars.next() {
10947                    match ch {
10948                        ' ' => {
10949                            reindented_line.push(' ');
10950                            col += 1;
10951                        }
10952                        '\t' => {
10953                            // \t are converted to spaces depending on the current column
10954                            let spaces_len = tab_size - (col % tab_size);
10955                            reindented_line.extend(&space_cache[spaces_len - 1]);
10956                            col += spaces_len;
10957                            changed = true;
10958                        }
10959                        _ => {
10960                            // If we dont append before break, the character is consumed
10961                            reindented_line.push(ch);
10962                            break;
10963                        }
10964                    }
10965                }
10966
10967                if !changed {
10968                    reindented_line.clear();
10969                    continue;
10970                }
10971                // Append the rest of the line and replace old reference with new one
10972                reindented_line.extend(chars);
10973                *line = Cow::Owned(reindented_line.clone());
10974                reindented_line.clear();
10975            }
10976        });
10977    }
10978
10979    pub fn convert_indentation_to_tabs(
10980        &mut self,
10981        _: &ConvertIndentationToTabs,
10982        window: &mut Window,
10983        cx: &mut Context<Self>,
10984    ) {
10985        let settings = self.buffer.read(cx).language_settings(cx);
10986        let tab_size = settings.tab_size.get() as usize;
10987
10988        self.manipulate_mutable_lines(window, cx, |lines| {
10989            // Allocates a reasonably sized buffer once for the whole loop
10990            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10991            // Avoids recomputing spaces that could be inserted many times
10992            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10993                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10994                .collect();
10995
10996            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10997                let mut chars = line.chars();
10998                let mut spaces_count = 0;
10999                let mut first_non_indent_char = None;
11000                let mut changed = false;
11001
11002                while let Some(ch) = chars.next() {
11003                    match ch {
11004                        ' ' => {
11005                            // Keep track of spaces. Append \t when we reach tab_size
11006                            spaces_count += 1;
11007                            changed = true;
11008                            if spaces_count == tab_size {
11009                                reindented_line.push('\t');
11010                                spaces_count = 0;
11011                            }
11012                        }
11013                        '\t' => {
11014                            reindented_line.push('\t');
11015                            spaces_count = 0;
11016                        }
11017                        _ => {
11018                            // Dont append it yet, we might have remaining spaces
11019                            first_non_indent_char = Some(ch);
11020                            break;
11021                        }
11022                    }
11023                }
11024
11025                if !changed {
11026                    reindented_line.clear();
11027                    continue;
11028                }
11029                // Remaining spaces that didn't make a full tab stop
11030                if spaces_count > 0 {
11031                    reindented_line.extend(&space_cache[spaces_count - 1]);
11032                }
11033                // If we consume an extra character that was not indentation, add it back
11034                if let Some(extra_char) = first_non_indent_char {
11035                    reindented_line.push(extra_char);
11036                }
11037                // Append the rest of the line and replace old reference with new one
11038                reindented_line.extend(chars);
11039                *line = Cow::Owned(reindented_line.clone());
11040                reindented_line.clear();
11041            }
11042        });
11043    }
11044
11045    pub fn convert_to_upper_case(
11046        &mut self,
11047        _: &ConvertToUpperCase,
11048        window: &mut Window,
11049        cx: &mut Context<Self>,
11050    ) {
11051        self.manipulate_text(window, cx, |text| text.to_uppercase())
11052    }
11053
11054    pub fn convert_to_lower_case(
11055        &mut self,
11056        _: &ConvertToLowerCase,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_text(window, cx, |text| text.to_lowercase())
11061    }
11062
11063    pub fn convert_to_title_case(
11064        &mut self,
11065        _: &ConvertToTitleCase,
11066        window: &mut Window,
11067        cx: &mut Context<Self>,
11068    ) {
11069        self.manipulate_text(window, cx, |text| {
11070            text.split('\n')
11071                .map(|line| line.to_case(Case::Title))
11072                .join("\n")
11073        })
11074    }
11075
11076    pub fn convert_to_snake_case(
11077        &mut self,
11078        _: &ConvertToSnakeCase,
11079        window: &mut Window,
11080        cx: &mut Context<Self>,
11081    ) {
11082        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11083    }
11084
11085    pub fn convert_to_kebab_case(
11086        &mut self,
11087        _: &ConvertToKebabCase,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11092    }
11093
11094    pub fn convert_to_upper_camel_case(
11095        &mut self,
11096        _: &ConvertToUpperCamelCase,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099    ) {
11100        self.manipulate_text(window, cx, |text| {
11101            text.split('\n')
11102                .map(|line| line.to_case(Case::UpperCamel))
11103                .join("\n")
11104        })
11105    }
11106
11107    pub fn convert_to_lower_camel_case(
11108        &mut self,
11109        _: &ConvertToLowerCamelCase,
11110        window: &mut Window,
11111        cx: &mut Context<Self>,
11112    ) {
11113        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11114    }
11115
11116    pub fn convert_to_opposite_case(
11117        &mut self,
11118        _: &ConvertToOppositeCase,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        self.manipulate_text(window, cx, |text| {
11123            text.chars()
11124                .fold(String::with_capacity(text.len()), |mut t, c| {
11125                    if c.is_uppercase() {
11126                        t.extend(c.to_lowercase());
11127                    } else {
11128                        t.extend(c.to_uppercase());
11129                    }
11130                    t
11131                })
11132        })
11133    }
11134
11135    pub fn convert_to_sentence_case(
11136        &mut self,
11137        _: &ConvertToSentenceCase,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11142    }
11143
11144    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11145        self.manipulate_text(window, cx, |text| {
11146            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11147            if has_upper_case_characters {
11148                text.to_lowercase()
11149            } else {
11150                text.to_uppercase()
11151            }
11152        })
11153    }
11154
11155    pub fn convert_to_rot13(
11156        &mut self,
11157        _: &ConvertToRot13,
11158        window: &mut Window,
11159        cx: &mut Context<Self>,
11160    ) {
11161        self.manipulate_text(window, cx, |text| {
11162            text.chars()
11163                .map(|c| match c {
11164                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11165                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11166                    _ => c,
11167                })
11168                .collect()
11169        })
11170    }
11171
11172    pub fn convert_to_rot47(
11173        &mut self,
11174        _: &ConvertToRot47,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        self.manipulate_text(window, cx, |text| {
11179            text.chars()
11180                .map(|c| {
11181                    let code_point = c as u32;
11182                    if code_point >= 33 && code_point <= 126 {
11183                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11184                    }
11185                    c
11186                })
11187                .collect()
11188        })
11189    }
11190
11191    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11192    where
11193        Fn: FnMut(&str) -> String,
11194    {
11195        let buffer = self.buffer.read(cx).snapshot(cx);
11196
11197        let mut new_selections = Vec::new();
11198        let mut edits = Vec::new();
11199        let mut selection_adjustment = 0i32;
11200
11201        for selection in self.selections.all::<usize>(cx) {
11202            let selection_is_empty = selection.is_empty();
11203
11204            let (start, end) = if selection_is_empty {
11205                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11206                (word_range.start, word_range.end)
11207            } else {
11208                (selection.start, selection.end)
11209            };
11210
11211            let text = buffer.text_for_range(start..end).collect::<String>();
11212            let old_length = text.len() as i32;
11213            let text = callback(&text);
11214
11215            new_selections.push(Selection {
11216                start: (start as i32 - selection_adjustment) as usize,
11217                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11218                goal: SelectionGoal::None,
11219                ..selection
11220            });
11221
11222            selection_adjustment += old_length - text.len() as i32;
11223
11224            edits.push((start..end, text));
11225        }
11226
11227        self.transact(window, cx, |this, window, cx| {
11228            this.buffer.update(cx, |buffer, cx| {
11229                buffer.edit(edits, None, cx);
11230            });
11231
11232            this.change_selections(Default::default(), window, cx, |s| {
11233                s.select(new_selections);
11234            });
11235
11236            this.request_autoscroll(Autoscroll::fit(), cx);
11237        });
11238    }
11239
11240    pub fn move_selection_on_drop(
11241        &mut self,
11242        selection: &Selection<Anchor>,
11243        target: DisplayPoint,
11244        is_cut: bool,
11245        window: &mut Window,
11246        cx: &mut Context<Self>,
11247    ) {
11248        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11249        let buffer = &display_map.buffer_snapshot;
11250        let mut edits = Vec::new();
11251        let insert_point = display_map
11252            .clip_point(target, Bias::Left)
11253            .to_point(&display_map);
11254        let text = buffer
11255            .text_for_range(selection.start..selection.end)
11256            .collect::<String>();
11257        if is_cut {
11258            edits.push(((selection.start..selection.end), String::new()));
11259        }
11260        let insert_anchor = buffer.anchor_before(insert_point);
11261        edits.push(((insert_anchor..insert_anchor), text));
11262        let last_edit_start = insert_anchor.bias_left(buffer);
11263        let last_edit_end = insert_anchor.bias_right(buffer);
11264        self.transact(window, cx, |this, window, cx| {
11265            this.buffer.update(cx, |buffer, cx| {
11266                buffer.edit(edits, None, cx);
11267            });
11268            this.change_selections(Default::default(), window, cx, |s| {
11269                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11270            });
11271        });
11272    }
11273
11274    pub fn clear_selection_drag_state(&mut self) {
11275        self.selection_drag_state = SelectionDragState::None;
11276    }
11277
11278    pub fn duplicate(
11279        &mut self,
11280        upwards: bool,
11281        whole_lines: bool,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284    ) {
11285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11286
11287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11288        let buffer = &display_map.buffer_snapshot;
11289        let selections = self.selections.all::<Point>(cx);
11290
11291        let mut edits = Vec::new();
11292        let mut selections_iter = selections.iter().peekable();
11293        while let Some(selection) = selections_iter.next() {
11294            let mut rows = selection.spanned_rows(false, &display_map);
11295            // duplicate line-wise
11296            if whole_lines || selection.start == selection.end {
11297                // Avoid duplicating the same lines twice.
11298                while let Some(next_selection) = selections_iter.peek() {
11299                    let next_rows = next_selection.spanned_rows(false, &display_map);
11300                    if next_rows.start < rows.end {
11301                        rows.end = next_rows.end;
11302                        selections_iter.next().unwrap();
11303                    } else {
11304                        break;
11305                    }
11306                }
11307
11308                // Copy the text from the selected row region and splice it either at the start
11309                // or end of the region.
11310                let start = Point::new(rows.start.0, 0);
11311                let end = Point::new(
11312                    rows.end.previous_row().0,
11313                    buffer.line_len(rows.end.previous_row()),
11314                );
11315                let text = buffer
11316                    .text_for_range(start..end)
11317                    .chain(Some("\n"))
11318                    .collect::<String>();
11319                let insert_location = if upwards {
11320                    Point::new(rows.end.0, 0)
11321                } else {
11322                    start
11323                };
11324                edits.push((insert_location..insert_location, text));
11325            } else {
11326                // duplicate character-wise
11327                let start = selection.start;
11328                let end = selection.end;
11329                let text = buffer.text_for_range(start..end).collect::<String>();
11330                edits.push((selection.end..selection.end, text));
11331            }
11332        }
11333
11334        self.transact(window, cx, |this, _, cx| {
11335            this.buffer.update(cx, |buffer, cx| {
11336                buffer.edit(edits, None, cx);
11337            });
11338
11339            this.request_autoscroll(Autoscroll::fit(), cx);
11340        });
11341    }
11342
11343    pub fn duplicate_line_up(
11344        &mut self,
11345        _: &DuplicateLineUp,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        self.duplicate(true, true, window, cx);
11350    }
11351
11352    pub fn duplicate_line_down(
11353        &mut self,
11354        _: &DuplicateLineDown,
11355        window: &mut Window,
11356        cx: &mut Context<Self>,
11357    ) {
11358        self.duplicate(false, true, window, cx);
11359    }
11360
11361    pub fn duplicate_selection(
11362        &mut self,
11363        _: &DuplicateSelection,
11364        window: &mut Window,
11365        cx: &mut Context<Self>,
11366    ) {
11367        self.duplicate(false, false, window, cx);
11368    }
11369
11370    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11372        if self.mode.is_single_line() {
11373            cx.propagate();
11374            return;
11375        }
11376
11377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11378        let buffer = self.buffer.read(cx).snapshot(cx);
11379
11380        let mut edits = Vec::new();
11381        let mut unfold_ranges = Vec::new();
11382        let mut refold_creases = Vec::new();
11383
11384        let selections = self.selections.all::<Point>(cx);
11385        let mut selections = selections.iter().peekable();
11386        let mut contiguous_row_selections = Vec::new();
11387        let mut new_selections = Vec::new();
11388
11389        while let Some(selection) = selections.next() {
11390            // Find all the selections that span a contiguous row range
11391            let (start_row, end_row) = consume_contiguous_rows(
11392                &mut contiguous_row_selections,
11393                selection,
11394                &display_map,
11395                &mut selections,
11396            );
11397
11398            // Move the text spanned by the row range to be before the line preceding the row range
11399            if start_row.0 > 0 {
11400                let range_to_move = Point::new(
11401                    start_row.previous_row().0,
11402                    buffer.line_len(start_row.previous_row()),
11403                )
11404                    ..Point::new(
11405                        end_row.previous_row().0,
11406                        buffer.line_len(end_row.previous_row()),
11407                    );
11408                let insertion_point = display_map
11409                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11410                    .0;
11411
11412                // Don't move lines across excerpts
11413                if buffer
11414                    .excerpt_containing(insertion_point..range_to_move.end)
11415                    .is_some()
11416                {
11417                    let text = buffer
11418                        .text_for_range(range_to_move.clone())
11419                        .flat_map(|s| s.chars())
11420                        .skip(1)
11421                        .chain(['\n'])
11422                        .collect::<String>();
11423
11424                    edits.push((
11425                        buffer.anchor_after(range_to_move.start)
11426                            ..buffer.anchor_before(range_to_move.end),
11427                        String::new(),
11428                    ));
11429                    let insertion_anchor = buffer.anchor_after(insertion_point);
11430                    edits.push((insertion_anchor..insertion_anchor, text));
11431
11432                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11433
11434                    // Move selections up
11435                    new_selections.extend(contiguous_row_selections.drain(..).map(
11436                        |mut selection| {
11437                            selection.start.row -= row_delta;
11438                            selection.end.row -= row_delta;
11439                            selection
11440                        },
11441                    ));
11442
11443                    // Move folds up
11444                    unfold_ranges.push(range_to_move.clone());
11445                    for fold in display_map.folds_in_range(
11446                        buffer.anchor_before(range_to_move.start)
11447                            ..buffer.anchor_after(range_to_move.end),
11448                    ) {
11449                        let mut start = fold.range.start.to_point(&buffer);
11450                        let mut end = fold.range.end.to_point(&buffer);
11451                        start.row -= row_delta;
11452                        end.row -= row_delta;
11453                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11454                    }
11455                }
11456            }
11457
11458            // If we didn't move line(s), preserve the existing selections
11459            new_selections.append(&mut contiguous_row_selections);
11460        }
11461
11462        self.transact(window, cx, |this, window, cx| {
11463            this.unfold_ranges(&unfold_ranges, true, true, cx);
11464            this.buffer.update(cx, |buffer, cx| {
11465                for (range, text) in edits {
11466                    buffer.edit([(range, text)], None, cx);
11467                }
11468            });
11469            this.fold_creases(refold_creases, true, window, cx);
11470            this.change_selections(Default::default(), window, cx, |s| {
11471                s.select(new_selections);
11472            })
11473        });
11474    }
11475
11476    pub fn move_line_down(
11477        &mut self,
11478        _: &MoveLineDown,
11479        window: &mut Window,
11480        cx: &mut Context<Self>,
11481    ) {
11482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11483        if self.mode.is_single_line() {
11484            cx.propagate();
11485            return;
11486        }
11487
11488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11489        let buffer = self.buffer.read(cx).snapshot(cx);
11490
11491        let mut edits = Vec::new();
11492        let mut unfold_ranges = Vec::new();
11493        let mut refold_creases = Vec::new();
11494
11495        let selections = self.selections.all::<Point>(cx);
11496        let mut selections = selections.iter().peekable();
11497        let mut contiguous_row_selections = Vec::new();
11498        let mut new_selections = Vec::new();
11499
11500        while let Some(selection) = selections.next() {
11501            // Find all the selections that span a contiguous row range
11502            let (start_row, end_row) = consume_contiguous_rows(
11503                &mut contiguous_row_selections,
11504                selection,
11505                &display_map,
11506                &mut selections,
11507            );
11508
11509            // Move the text spanned by the row range to be after the last line of the row range
11510            if end_row.0 <= buffer.max_point().row {
11511                let range_to_move =
11512                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11513                let insertion_point = display_map
11514                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11515                    .0;
11516
11517                // Don't move lines across excerpt boundaries
11518                if buffer
11519                    .excerpt_containing(range_to_move.start..insertion_point)
11520                    .is_some()
11521                {
11522                    let mut text = String::from("\n");
11523                    text.extend(buffer.text_for_range(range_to_move.clone()));
11524                    text.pop(); // Drop trailing newline
11525                    edits.push((
11526                        buffer.anchor_after(range_to_move.start)
11527                            ..buffer.anchor_before(range_to_move.end),
11528                        String::new(),
11529                    ));
11530                    let insertion_anchor = buffer.anchor_after(insertion_point);
11531                    edits.push((insertion_anchor..insertion_anchor, text));
11532
11533                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11534
11535                    // Move selections down
11536                    new_selections.extend(contiguous_row_selections.drain(..).map(
11537                        |mut selection| {
11538                            selection.start.row += row_delta;
11539                            selection.end.row += row_delta;
11540                            selection
11541                        },
11542                    ));
11543
11544                    // Move folds down
11545                    unfold_ranges.push(range_to_move.clone());
11546                    for fold in display_map.folds_in_range(
11547                        buffer.anchor_before(range_to_move.start)
11548                            ..buffer.anchor_after(range_to_move.end),
11549                    ) {
11550                        let mut start = fold.range.start.to_point(&buffer);
11551                        let mut end = fold.range.end.to_point(&buffer);
11552                        start.row += row_delta;
11553                        end.row += row_delta;
11554                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11555                    }
11556                }
11557            }
11558
11559            // If we didn't move line(s), preserve the existing selections
11560            new_selections.append(&mut contiguous_row_selections);
11561        }
11562
11563        self.transact(window, cx, |this, window, cx| {
11564            this.unfold_ranges(&unfold_ranges, true, true, cx);
11565            this.buffer.update(cx, |buffer, cx| {
11566                for (range, text) in edits {
11567                    buffer.edit([(range, text)], None, cx);
11568                }
11569            });
11570            this.fold_creases(refold_creases, true, window, cx);
11571            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11572        });
11573    }
11574
11575    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11577        let text_layout_details = &self.text_layout_details(window);
11578        self.transact(window, cx, |this, window, cx| {
11579            let edits = this.change_selections(Default::default(), window, cx, |s| {
11580                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11581                s.move_with(|display_map, selection| {
11582                    if !selection.is_empty() {
11583                        return;
11584                    }
11585
11586                    let mut head = selection.head();
11587                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11588                    if head.column() == display_map.line_len(head.row()) {
11589                        transpose_offset = display_map
11590                            .buffer_snapshot
11591                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11592                    }
11593
11594                    if transpose_offset == 0 {
11595                        return;
11596                    }
11597
11598                    *head.column_mut() += 1;
11599                    head = display_map.clip_point(head, Bias::Right);
11600                    let goal = SelectionGoal::HorizontalPosition(
11601                        display_map
11602                            .x_for_display_point(head, text_layout_details)
11603                            .into(),
11604                    );
11605                    selection.collapse_to(head, goal);
11606
11607                    let transpose_start = display_map
11608                        .buffer_snapshot
11609                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11610                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11611                        let transpose_end = display_map
11612                            .buffer_snapshot
11613                            .clip_offset(transpose_offset + 1, Bias::Right);
11614                        if let Some(ch) =
11615                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11616                        {
11617                            edits.push((transpose_start..transpose_offset, String::new()));
11618                            edits.push((transpose_end..transpose_end, ch.to_string()));
11619                        }
11620                    }
11621                });
11622                edits
11623            });
11624            this.buffer
11625                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11626            let selections = this.selections.all::<usize>(cx);
11627            this.change_selections(Default::default(), window, cx, |s| {
11628                s.select(selections);
11629            });
11630        });
11631    }
11632
11633    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11635        if self.mode.is_single_line() {
11636            cx.propagate();
11637            return;
11638        }
11639
11640        self.rewrap_impl(RewrapOptions::default(), cx)
11641    }
11642
11643    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11644        let buffer = self.buffer.read(cx).snapshot(cx);
11645        let selections = self.selections.all::<Point>(cx);
11646
11647        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11648        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11649            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11650                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11651                .peekable();
11652
11653            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11654                row
11655            } else {
11656                return Vec::new();
11657            };
11658
11659            let language_settings = buffer.language_settings_at(selection.head(), cx);
11660            let language_scope = buffer.language_scope_at(selection.head());
11661
11662            let indent_and_prefix_for_row =
11663                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11664                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11665                    let (comment_prefix, rewrap_prefix) =
11666                        if let Some(language_scope) = &language_scope {
11667                            let indent_end = Point::new(row, indent.len);
11668                            let comment_prefix = language_scope
11669                                .line_comment_prefixes()
11670                                .iter()
11671                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11672                                .map(|prefix| prefix.to_string());
11673                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11674                            let line_text_after_indent = buffer
11675                                .text_for_range(indent_end..line_end)
11676                                .collect::<String>();
11677                            let rewrap_prefix = language_scope
11678                                .rewrap_prefixes()
11679                                .iter()
11680                                .find_map(|prefix_regex| {
11681                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11682                                        if mat.start() == 0 {
11683                                            Some(mat.as_str().to_string())
11684                                        } else {
11685                                            None
11686                                        }
11687                                    })
11688                                })
11689                                .flatten();
11690                            (comment_prefix, rewrap_prefix)
11691                        } else {
11692                            (None, None)
11693                        };
11694                    (indent, comment_prefix, rewrap_prefix)
11695                };
11696
11697            let mut ranges = Vec::new();
11698            let from_empty_selection = selection.is_empty();
11699
11700            let mut current_range_start = first_row;
11701            let mut prev_row = first_row;
11702            let (
11703                mut current_range_indent,
11704                mut current_range_comment_prefix,
11705                mut current_range_rewrap_prefix,
11706            ) = indent_and_prefix_for_row(first_row);
11707
11708            for row in non_blank_rows_iter.skip(1) {
11709                let has_paragraph_break = row > prev_row + 1;
11710
11711                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11712                    indent_and_prefix_for_row(row);
11713
11714                let has_indent_change = row_indent != current_range_indent;
11715                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11716
11717                let has_boundary_change = has_comment_change
11718                    || row_rewrap_prefix.is_some()
11719                    || (has_indent_change && current_range_comment_prefix.is_some());
11720
11721                if has_paragraph_break || has_boundary_change {
11722                    ranges.push((
11723                        language_settings.clone(),
11724                        Point::new(current_range_start, 0)
11725                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11726                        current_range_indent,
11727                        current_range_comment_prefix.clone(),
11728                        current_range_rewrap_prefix.clone(),
11729                        from_empty_selection,
11730                    ));
11731                    current_range_start = row;
11732                    current_range_indent = row_indent;
11733                    current_range_comment_prefix = row_comment_prefix;
11734                    current_range_rewrap_prefix = row_rewrap_prefix;
11735                }
11736                prev_row = row;
11737            }
11738
11739            ranges.push((
11740                language_settings.clone(),
11741                Point::new(current_range_start, 0)
11742                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11743                current_range_indent,
11744                current_range_comment_prefix,
11745                current_range_rewrap_prefix,
11746                from_empty_selection,
11747            ));
11748
11749            ranges
11750        });
11751
11752        let mut edits = Vec::new();
11753        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11754
11755        for (
11756            language_settings,
11757            wrap_range,
11758            indent_size,
11759            comment_prefix,
11760            rewrap_prefix,
11761            from_empty_selection,
11762        ) in wrap_ranges
11763        {
11764            let mut start_row = wrap_range.start.row;
11765            let mut end_row = wrap_range.end.row;
11766
11767            // Skip selections that overlap with a range that has already been rewrapped.
11768            let selection_range = start_row..end_row;
11769            if rewrapped_row_ranges
11770                .iter()
11771                .any(|range| range.overlaps(&selection_range))
11772            {
11773                continue;
11774            }
11775
11776            let tab_size = language_settings.tab_size;
11777
11778            let indent_prefix = indent_size.chars().collect::<String>();
11779            let mut line_prefix = indent_prefix.clone();
11780            let mut inside_comment = false;
11781            if let Some(prefix) = &comment_prefix {
11782                line_prefix.push_str(prefix);
11783                inside_comment = true;
11784            }
11785            if let Some(prefix) = &rewrap_prefix {
11786                line_prefix.push_str(prefix);
11787            }
11788
11789            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11790                RewrapBehavior::InComments => inside_comment,
11791                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11792                RewrapBehavior::Anywhere => true,
11793            };
11794
11795            let should_rewrap = options.override_language_settings
11796                || allow_rewrap_based_on_language
11797                || self.hard_wrap.is_some();
11798            if !should_rewrap {
11799                continue;
11800            }
11801
11802            if from_empty_selection {
11803                'expand_upwards: while start_row > 0 {
11804                    let prev_row = start_row - 1;
11805                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11806                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11807                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11808                    {
11809                        start_row = prev_row;
11810                    } else {
11811                        break 'expand_upwards;
11812                    }
11813                }
11814
11815                'expand_downwards: while end_row < buffer.max_point().row {
11816                    let next_row = end_row + 1;
11817                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11818                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11819                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11820                    {
11821                        end_row = next_row;
11822                    } else {
11823                        break 'expand_downwards;
11824                    }
11825                }
11826            }
11827
11828            let start = Point::new(start_row, 0);
11829            let start_offset = start.to_offset(&buffer);
11830            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11831            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11832            let Some(lines_without_prefixes) = selection_text
11833                .lines()
11834                .enumerate()
11835                .map(|(ix, line)| {
11836                    let line_trimmed = line.trim_start();
11837                    if rewrap_prefix.is_some() && ix > 0 {
11838                        Ok(line_trimmed)
11839                    } else {
11840                        line_trimmed
11841                            .strip_prefix(&line_prefix.trim_start())
11842                            .with_context(|| {
11843                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11844                            })
11845                    }
11846                })
11847                .collect::<Result<Vec<_>, _>>()
11848                .log_err()
11849            else {
11850                continue;
11851            };
11852
11853            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11854                buffer
11855                    .language_settings_at(Point::new(start_row, 0), cx)
11856                    .preferred_line_length as usize
11857            });
11858
11859            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11860                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11861            } else {
11862                line_prefix.clone()
11863            };
11864
11865            let wrapped_text = wrap_with_prefix(
11866                line_prefix,
11867                subsequent_lines_prefix,
11868                lines_without_prefixes.join("\n"),
11869                wrap_column,
11870                tab_size,
11871                options.preserve_existing_whitespace,
11872            );
11873
11874            // TODO: should always use char-based diff while still supporting cursor behavior that
11875            // matches vim.
11876            let mut diff_options = DiffOptions::default();
11877            if options.override_language_settings {
11878                diff_options.max_word_diff_len = 0;
11879                diff_options.max_word_diff_line_count = 0;
11880            } else {
11881                diff_options.max_word_diff_len = usize::MAX;
11882                diff_options.max_word_diff_line_count = usize::MAX;
11883            }
11884
11885            for (old_range, new_text) in
11886                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11887            {
11888                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11889                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11890                edits.push((edit_start..edit_end, new_text));
11891            }
11892
11893            rewrapped_row_ranges.push(start_row..=end_row);
11894        }
11895
11896        self.buffer
11897            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11898    }
11899
11900    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11901        let mut text = String::new();
11902        let buffer = self.buffer.read(cx).snapshot(cx);
11903        let mut selections = self.selections.all::<Point>(cx);
11904        let mut clipboard_selections = Vec::with_capacity(selections.len());
11905        {
11906            let max_point = buffer.max_point();
11907            let mut is_first = true;
11908            for selection in &mut selections {
11909                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11910                if is_entire_line {
11911                    selection.start = Point::new(selection.start.row, 0);
11912                    if !selection.is_empty() && selection.end.column == 0 {
11913                        selection.end = cmp::min(max_point, selection.end);
11914                    } else {
11915                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11916                    }
11917                    selection.goal = SelectionGoal::None;
11918                }
11919                if is_first {
11920                    is_first = false;
11921                } else {
11922                    text += "\n";
11923                }
11924                let mut len = 0;
11925                for chunk in buffer.text_for_range(selection.start..selection.end) {
11926                    text.push_str(chunk);
11927                    len += chunk.len();
11928                }
11929                clipboard_selections.push(ClipboardSelection {
11930                    len,
11931                    is_entire_line,
11932                    first_line_indent: buffer
11933                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11934                        .len,
11935                });
11936            }
11937        }
11938
11939        self.transact(window, cx, |this, window, cx| {
11940            this.change_selections(Default::default(), window, cx, |s| {
11941                s.select(selections);
11942            });
11943            this.insert("", window, cx);
11944        });
11945        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11946    }
11947
11948    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11950        let item = self.cut_common(window, cx);
11951        cx.write_to_clipboard(item);
11952    }
11953
11954    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11956        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11957            s.move_with(|snapshot, sel| {
11958                if sel.is_empty() {
11959                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11960                }
11961            });
11962        });
11963        let item = self.cut_common(window, cx);
11964        cx.set_global(KillRing(item))
11965    }
11966
11967    pub fn kill_ring_yank(
11968        &mut self,
11969        _: &KillRingYank,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11974        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11975            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11976                (kill_ring.text().to_string(), kill_ring.metadata_json())
11977            } else {
11978                return;
11979            }
11980        } else {
11981            return;
11982        };
11983        self.do_paste(&text, metadata, false, window, cx);
11984    }
11985
11986    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11987        self.do_copy(true, cx);
11988    }
11989
11990    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11991        self.do_copy(false, cx);
11992    }
11993
11994    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11995        let selections = self.selections.all::<Point>(cx);
11996        let buffer = self.buffer.read(cx).read(cx);
11997        let mut text = String::new();
11998
11999        let mut clipboard_selections = Vec::with_capacity(selections.len());
12000        {
12001            let max_point = buffer.max_point();
12002            let mut is_first = true;
12003            for selection in &selections {
12004                let mut start = selection.start;
12005                let mut end = selection.end;
12006                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12007                if is_entire_line {
12008                    start = Point::new(start.row, 0);
12009                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12010                }
12011
12012                let mut trimmed_selections = Vec::new();
12013                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12014                    let row = MultiBufferRow(start.row);
12015                    let first_indent = buffer.indent_size_for_line(row);
12016                    if first_indent.len == 0 || start.column > first_indent.len {
12017                        trimmed_selections.push(start..end);
12018                    } else {
12019                        trimmed_selections.push(
12020                            Point::new(row.0, first_indent.len)
12021                                ..Point::new(row.0, buffer.line_len(row)),
12022                        );
12023                        for row in start.row + 1..=end.row {
12024                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12025                            if row == end.row {
12026                                line_len = end.column;
12027                            }
12028                            if line_len == 0 {
12029                                trimmed_selections
12030                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12031                                continue;
12032                            }
12033                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12034                            if row_indent_size.len >= first_indent.len {
12035                                trimmed_selections.push(
12036                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12037                                );
12038                            } else {
12039                                trimmed_selections.clear();
12040                                trimmed_selections.push(start..end);
12041                                break;
12042                            }
12043                        }
12044                    }
12045                } else {
12046                    trimmed_selections.push(start..end);
12047                }
12048
12049                for trimmed_range in trimmed_selections {
12050                    if is_first {
12051                        is_first = false;
12052                    } else {
12053                        text += "\n";
12054                    }
12055                    let mut len = 0;
12056                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12057                        text.push_str(chunk);
12058                        len += chunk.len();
12059                    }
12060                    clipboard_selections.push(ClipboardSelection {
12061                        len,
12062                        is_entire_line,
12063                        first_line_indent: buffer
12064                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12065                            .len,
12066                    });
12067                }
12068            }
12069        }
12070
12071        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12072            text,
12073            clipboard_selections,
12074        ));
12075    }
12076
12077    pub fn do_paste(
12078        &mut self,
12079        text: &String,
12080        clipboard_selections: Option<Vec<ClipboardSelection>>,
12081        handle_entire_lines: bool,
12082        window: &mut Window,
12083        cx: &mut Context<Self>,
12084    ) {
12085        if self.read_only(cx) {
12086            return;
12087        }
12088
12089        let clipboard_text = Cow::Borrowed(text);
12090
12091        self.transact(window, cx, |this, window, cx| {
12092            if let Some(mut clipboard_selections) = clipboard_selections {
12093                let old_selections = this.selections.all::<usize>(cx);
12094                let all_selections_were_entire_line =
12095                    clipboard_selections.iter().all(|s| s.is_entire_line);
12096                let first_selection_indent_column =
12097                    clipboard_selections.first().map(|s| s.first_line_indent);
12098                if clipboard_selections.len() != old_selections.len() {
12099                    clipboard_selections.drain(..);
12100                }
12101                let cursor_offset = this.selections.last::<usize>(cx).head();
12102                let mut auto_indent_on_paste = true;
12103
12104                this.buffer.update(cx, |buffer, cx| {
12105                    let snapshot = buffer.read(cx);
12106                    auto_indent_on_paste = snapshot
12107                        .language_settings_at(cursor_offset, cx)
12108                        .auto_indent_on_paste;
12109
12110                    let mut start_offset = 0;
12111                    let mut edits = Vec::new();
12112                    let mut original_indent_columns = Vec::new();
12113                    for (ix, selection) in old_selections.iter().enumerate() {
12114                        let to_insert;
12115                        let entire_line;
12116                        let original_indent_column;
12117                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12118                            let end_offset = start_offset + clipboard_selection.len;
12119                            to_insert = &clipboard_text[start_offset..end_offset];
12120                            entire_line = clipboard_selection.is_entire_line;
12121                            start_offset = end_offset + 1;
12122                            original_indent_column = Some(clipboard_selection.first_line_indent);
12123                        } else {
12124                            to_insert = clipboard_text.as_str();
12125                            entire_line = all_selections_were_entire_line;
12126                            original_indent_column = first_selection_indent_column
12127                        }
12128
12129                        // If the corresponding selection was empty when this slice of the
12130                        // clipboard text was written, then the entire line containing the
12131                        // selection was copied. If this selection is also currently empty,
12132                        // then paste the line before the current line of the buffer.
12133                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12134                            let column = selection.start.to_point(&snapshot).column as usize;
12135                            let line_start = selection.start - column;
12136                            line_start..line_start
12137                        } else {
12138                            selection.range()
12139                        };
12140
12141                        edits.push((range, to_insert));
12142                        original_indent_columns.push(original_indent_column);
12143                    }
12144                    drop(snapshot);
12145
12146                    buffer.edit(
12147                        edits,
12148                        if auto_indent_on_paste {
12149                            Some(AutoindentMode::Block {
12150                                original_indent_columns,
12151                            })
12152                        } else {
12153                            None
12154                        },
12155                        cx,
12156                    );
12157                });
12158
12159                let selections = this.selections.all::<usize>(cx);
12160                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12161            } else {
12162                this.insert(&clipboard_text, window, cx);
12163            }
12164        });
12165    }
12166
12167    pub fn diff_clipboard_with_selection(
12168        &mut self,
12169        _: &DiffClipboardWithSelection,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        let selections = self.selections.all::<usize>(cx);
12174
12175        if selections.is_empty() {
12176            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12177            return;
12178        };
12179
12180        let clipboard_text = match cx.read_from_clipboard() {
12181            Some(item) => match item.entries().first() {
12182                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12183                _ => None,
12184            },
12185            None => None,
12186        };
12187
12188        let Some(clipboard_text) = clipboard_text else {
12189            log::warn!("Clipboard doesn't contain text.");
12190            return;
12191        };
12192
12193        window.dispatch_action(
12194            Box::new(DiffClipboardWithSelectionData {
12195                clipboard_text,
12196                editor: cx.entity(),
12197            }),
12198            cx,
12199        );
12200    }
12201
12202    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12204        if let Some(item) = cx.read_from_clipboard() {
12205            let entries = item.entries();
12206
12207            match entries.first() {
12208                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12209                // of all the pasted entries.
12210                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12211                    .do_paste(
12212                        clipboard_string.text(),
12213                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12214                        true,
12215                        window,
12216                        cx,
12217                    ),
12218                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12219            }
12220        }
12221    }
12222
12223    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12224        if self.read_only(cx) {
12225            return;
12226        }
12227
12228        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12229
12230        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12231            if let Some((selections, _)) =
12232                self.selection_history.transaction(transaction_id).cloned()
12233            {
12234                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12235                    s.select_anchors(selections.to_vec());
12236                });
12237            } else {
12238                log::error!(
12239                    "No entry in selection_history found for undo. \
12240                     This may correspond to a bug where undo does not update the selection. \
12241                     If this is occurring, please add details to \
12242                     https://github.com/zed-industries/zed/issues/22692"
12243                );
12244            }
12245            self.request_autoscroll(Autoscroll::fit(), cx);
12246            self.unmark_text(window, cx);
12247            self.refresh_inline_completion(true, false, window, cx);
12248            cx.emit(EditorEvent::Edited { transaction_id });
12249            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12250        }
12251    }
12252
12253    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12254        if self.read_only(cx) {
12255            return;
12256        }
12257
12258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12259
12260        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12261            if let Some((_, Some(selections))) =
12262                self.selection_history.transaction(transaction_id).cloned()
12263            {
12264                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12265                    s.select_anchors(selections.to_vec());
12266                });
12267            } else {
12268                log::error!(
12269                    "No entry in selection_history found for redo. \
12270                     This may correspond to a bug where undo does not update the selection. \
12271                     If this is occurring, please add details to \
12272                     https://github.com/zed-industries/zed/issues/22692"
12273                );
12274            }
12275            self.request_autoscroll(Autoscroll::fit(), cx);
12276            self.unmark_text(window, cx);
12277            self.refresh_inline_completion(true, false, window, cx);
12278            cx.emit(EditorEvent::Edited { transaction_id });
12279        }
12280    }
12281
12282    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12283        self.buffer
12284            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12285    }
12286
12287    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12288        self.buffer
12289            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12290    }
12291
12292    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12294        self.change_selections(Default::default(), window, cx, |s| {
12295            s.move_with(|map, selection| {
12296                let cursor = if selection.is_empty() {
12297                    movement::left(map, selection.start)
12298                } else {
12299                    selection.start
12300                };
12301                selection.collapse_to(cursor, SelectionGoal::None);
12302            });
12303        })
12304    }
12305
12306    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12308        self.change_selections(Default::default(), window, cx, |s| {
12309            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12310        })
12311    }
12312
12313    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12315        self.change_selections(Default::default(), window, cx, |s| {
12316            s.move_with(|map, selection| {
12317                let cursor = if selection.is_empty() {
12318                    movement::right(map, selection.end)
12319                } else {
12320                    selection.end
12321                };
12322                selection.collapse_to(cursor, SelectionGoal::None)
12323            });
12324        })
12325    }
12326
12327    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12328        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12329        self.change_selections(Default::default(), window, cx, |s| {
12330            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12331        })
12332    }
12333
12334    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12335        if self.take_rename(true, window, cx).is_some() {
12336            return;
12337        }
12338
12339        if self.mode.is_single_line() {
12340            cx.propagate();
12341            return;
12342        }
12343
12344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12345
12346        let text_layout_details = &self.text_layout_details(window);
12347        let selection_count = self.selections.count();
12348        let first_selection = self.selections.first_anchor();
12349
12350        self.change_selections(Default::default(), window, cx, |s| {
12351            s.move_with(|map, selection| {
12352                if !selection.is_empty() {
12353                    selection.goal = SelectionGoal::None;
12354                }
12355                let (cursor, goal) = movement::up(
12356                    map,
12357                    selection.start,
12358                    selection.goal,
12359                    false,
12360                    text_layout_details,
12361                );
12362                selection.collapse_to(cursor, goal);
12363            });
12364        });
12365
12366        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12367        {
12368            cx.propagate();
12369        }
12370    }
12371
12372    pub fn move_up_by_lines(
12373        &mut self,
12374        action: &MoveUpByLines,
12375        window: &mut Window,
12376        cx: &mut Context<Self>,
12377    ) {
12378        if self.take_rename(true, window, cx).is_some() {
12379            return;
12380        }
12381
12382        if self.mode.is_single_line() {
12383            cx.propagate();
12384            return;
12385        }
12386
12387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12388
12389        let text_layout_details = &self.text_layout_details(window);
12390
12391        self.change_selections(Default::default(), window, cx, |s| {
12392            s.move_with(|map, selection| {
12393                if !selection.is_empty() {
12394                    selection.goal = SelectionGoal::None;
12395                }
12396                let (cursor, goal) = movement::up_by_rows(
12397                    map,
12398                    selection.start,
12399                    action.lines,
12400                    selection.goal,
12401                    false,
12402                    text_layout_details,
12403                );
12404                selection.collapse_to(cursor, goal);
12405            });
12406        })
12407    }
12408
12409    pub fn move_down_by_lines(
12410        &mut self,
12411        action: &MoveDownByLines,
12412        window: &mut Window,
12413        cx: &mut Context<Self>,
12414    ) {
12415        if self.take_rename(true, window, cx).is_some() {
12416            return;
12417        }
12418
12419        if self.mode.is_single_line() {
12420            cx.propagate();
12421            return;
12422        }
12423
12424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12425
12426        let text_layout_details = &self.text_layout_details(window);
12427
12428        self.change_selections(Default::default(), window, cx, |s| {
12429            s.move_with(|map, selection| {
12430                if !selection.is_empty() {
12431                    selection.goal = SelectionGoal::None;
12432                }
12433                let (cursor, goal) = movement::down_by_rows(
12434                    map,
12435                    selection.start,
12436                    action.lines,
12437                    selection.goal,
12438                    false,
12439                    text_layout_details,
12440                );
12441                selection.collapse_to(cursor, goal);
12442            });
12443        })
12444    }
12445
12446    pub fn select_down_by_lines(
12447        &mut self,
12448        action: &SelectDownByLines,
12449        window: &mut Window,
12450        cx: &mut Context<Self>,
12451    ) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12453        let text_layout_details = &self.text_layout_details(window);
12454        self.change_selections(Default::default(), window, cx, |s| {
12455            s.move_heads_with(|map, head, goal| {
12456                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12457            })
12458        })
12459    }
12460
12461    pub fn select_up_by_lines(
12462        &mut self,
12463        action: &SelectUpByLines,
12464        window: &mut Window,
12465        cx: &mut Context<Self>,
12466    ) {
12467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12468        let text_layout_details = &self.text_layout_details(window);
12469        self.change_selections(Default::default(), window, cx, |s| {
12470            s.move_heads_with(|map, head, goal| {
12471                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12472            })
12473        })
12474    }
12475
12476    pub fn select_page_up(
12477        &mut self,
12478        _: &SelectPageUp,
12479        window: &mut Window,
12480        cx: &mut Context<Self>,
12481    ) {
12482        let Some(row_count) = self.visible_row_count() else {
12483            return;
12484        };
12485
12486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12487
12488        let text_layout_details = &self.text_layout_details(window);
12489
12490        self.change_selections(Default::default(), window, cx, |s| {
12491            s.move_heads_with(|map, head, goal| {
12492                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12493            })
12494        })
12495    }
12496
12497    pub fn move_page_up(
12498        &mut self,
12499        action: &MovePageUp,
12500        window: &mut Window,
12501        cx: &mut Context<Self>,
12502    ) {
12503        if self.take_rename(true, window, cx).is_some() {
12504            return;
12505        }
12506
12507        if self
12508            .context_menu
12509            .borrow_mut()
12510            .as_mut()
12511            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12512            .unwrap_or(false)
12513        {
12514            return;
12515        }
12516
12517        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12518            cx.propagate();
12519            return;
12520        }
12521
12522        let Some(row_count) = self.visible_row_count() else {
12523            return;
12524        };
12525
12526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12527
12528        let effects = if action.center_cursor {
12529            SelectionEffects::scroll(Autoscroll::center())
12530        } else {
12531            SelectionEffects::default()
12532        };
12533
12534        let text_layout_details = &self.text_layout_details(window);
12535
12536        self.change_selections(effects, window, cx, |s| {
12537            s.move_with(|map, selection| {
12538                if !selection.is_empty() {
12539                    selection.goal = SelectionGoal::None;
12540                }
12541                let (cursor, goal) = movement::up_by_rows(
12542                    map,
12543                    selection.end,
12544                    row_count,
12545                    selection.goal,
12546                    false,
12547                    text_layout_details,
12548                );
12549                selection.collapse_to(cursor, goal);
12550            });
12551        });
12552    }
12553
12554    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12556        let text_layout_details = &self.text_layout_details(window);
12557        self.change_selections(Default::default(), window, cx, |s| {
12558            s.move_heads_with(|map, head, goal| {
12559                movement::up(map, head, goal, false, text_layout_details)
12560            })
12561        })
12562    }
12563
12564    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12565        self.take_rename(true, window, cx);
12566
12567        if self.mode.is_single_line() {
12568            cx.propagate();
12569            return;
12570        }
12571
12572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12573
12574        let text_layout_details = &self.text_layout_details(window);
12575        let selection_count = self.selections.count();
12576        let first_selection = self.selections.first_anchor();
12577
12578        self.change_selections(Default::default(), window, cx, |s| {
12579            s.move_with(|map, selection| {
12580                if !selection.is_empty() {
12581                    selection.goal = SelectionGoal::None;
12582                }
12583                let (cursor, goal) = movement::down(
12584                    map,
12585                    selection.end,
12586                    selection.goal,
12587                    false,
12588                    text_layout_details,
12589                );
12590                selection.collapse_to(cursor, goal);
12591            });
12592        });
12593
12594        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12595        {
12596            cx.propagate();
12597        }
12598    }
12599
12600    pub fn select_page_down(
12601        &mut self,
12602        _: &SelectPageDown,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let Some(row_count) = self.visible_row_count() else {
12607            return;
12608        };
12609
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12611
12612        let text_layout_details = &self.text_layout_details(window);
12613
12614        self.change_selections(Default::default(), window, cx, |s| {
12615            s.move_heads_with(|map, head, goal| {
12616                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12617            })
12618        })
12619    }
12620
12621    pub fn move_page_down(
12622        &mut self,
12623        action: &MovePageDown,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        if self.take_rename(true, window, cx).is_some() {
12628            return;
12629        }
12630
12631        if self
12632            .context_menu
12633            .borrow_mut()
12634            .as_mut()
12635            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12636            .unwrap_or(false)
12637        {
12638            return;
12639        }
12640
12641        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12642            cx.propagate();
12643            return;
12644        }
12645
12646        let Some(row_count) = self.visible_row_count() else {
12647            return;
12648        };
12649
12650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12651
12652        let effects = if action.center_cursor {
12653            SelectionEffects::scroll(Autoscroll::center())
12654        } else {
12655            SelectionEffects::default()
12656        };
12657
12658        let text_layout_details = &self.text_layout_details(window);
12659        self.change_selections(effects, window, cx, |s| {
12660            s.move_with(|map, selection| {
12661                if !selection.is_empty() {
12662                    selection.goal = SelectionGoal::None;
12663                }
12664                let (cursor, goal) = movement::down_by_rows(
12665                    map,
12666                    selection.end,
12667                    row_count,
12668                    selection.goal,
12669                    false,
12670                    text_layout_details,
12671                );
12672                selection.collapse_to(cursor, goal);
12673            });
12674        });
12675    }
12676
12677    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        let text_layout_details = &self.text_layout_details(window);
12680        self.change_selections(Default::default(), window, cx, |s| {
12681            s.move_heads_with(|map, head, goal| {
12682                movement::down(map, head, goal, false, text_layout_details)
12683            })
12684        });
12685    }
12686
12687    pub fn context_menu_first(
12688        &mut self,
12689        _: &ContextMenuFirst,
12690        window: &mut Window,
12691        cx: &mut Context<Self>,
12692    ) {
12693        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12694            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12695        }
12696    }
12697
12698    pub fn context_menu_prev(
12699        &mut self,
12700        _: &ContextMenuPrevious,
12701        window: &mut Window,
12702        cx: &mut Context<Self>,
12703    ) {
12704        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12705            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12706        }
12707    }
12708
12709    pub fn context_menu_next(
12710        &mut self,
12711        _: &ContextMenuNext,
12712        window: &mut Window,
12713        cx: &mut Context<Self>,
12714    ) {
12715        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12716            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12717        }
12718    }
12719
12720    pub fn context_menu_last(
12721        &mut self,
12722        _: &ContextMenuLast,
12723        window: &mut Window,
12724        cx: &mut Context<Self>,
12725    ) {
12726        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12727            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12728        }
12729    }
12730
12731    pub fn signature_help_prev(
12732        &mut self,
12733        _: &SignatureHelpPrevious,
12734        _: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        if let Some(popover) = self.signature_help_state.popover_mut() {
12738            if popover.current_signature == 0 {
12739                popover.current_signature = popover.signatures.len() - 1;
12740            } else {
12741                popover.current_signature -= 1;
12742            }
12743            cx.notify();
12744        }
12745    }
12746
12747    pub fn signature_help_next(
12748        &mut self,
12749        _: &SignatureHelpNext,
12750        _: &mut Window,
12751        cx: &mut Context<Self>,
12752    ) {
12753        if let Some(popover) = self.signature_help_state.popover_mut() {
12754            if popover.current_signature + 1 == popover.signatures.len() {
12755                popover.current_signature = 0;
12756            } else {
12757                popover.current_signature += 1;
12758            }
12759            cx.notify();
12760        }
12761    }
12762
12763    pub fn move_to_previous_word_start(
12764        &mut self,
12765        _: &MoveToPreviousWordStart,
12766        window: &mut Window,
12767        cx: &mut Context<Self>,
12768    ) {
12769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12770        self.change_selections(Default::default(), window, cx, |s| {
12771            s.move_cursors_with(|map, head, _| {
12772                (
12773                    movement::previous_word_start(map, head),
12774                    SelectionGoal::None,
12775                )
12776            });
12777        })
12778    }
12779
12780    pub fn move_to_previous_subword_start(
12781        &mut self,
12782        _: &MoveToPreviousSubwordStart,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12787        self.change_selections(Default::default(), window, cx, |s| {
12788            s.move_cursors_with(|map, head, _| {
12789                (
12790                    movement::previous_subword_start(map, head),
12791                    SelectionGoal::None,
12792                )
12793            });
12794        })
12795    }
12796
12797    pub fn select_to_previous_word_start(
12798        &mut self,
12799        _: &SelectToPreviousWordStart,
12800        window: &mut Window,
12801        cx: &mut Context<Self>,
12802    ) {
12803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12804        self.change_selections(Default::default(), window, cx, |s| {
12805            s.move_heads_with(|map, head, _| {
12806                (
12807                    movement::previous_word_start(map, head),
12808                    SelectionGoal::None,
12809                )
12810            });
12811        })
12812    }
12813
12814    pub fn select_to_previous_subword_start(
12815        &mut self,
12816        _: &SelectToPreviousSubwordStart,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        self.change_selections(Default::default(), window, cx, |s| {
12822            s.move_heads_with(|map, head, _| {
12823                (
12824                    movement::previous_subword_start(map, head),
12825                    SelectionGoal::None,
12826                )
12827            });
12828        })
12829    }
12830
12831    pub fn delete_to_previous_word_start(
12832        &mut self,
12833        action: &DeleteToPreviousWordStart,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12838        self.transact(window, cx, |this, window, cx| {
12839            this.select_autoclose_pair(window, cx);
12840            this.change_selections(Default::default(), window, cx, |s| {
12841                s.move_with(|map, selection| {
12842                    if selection.is_empty() {
12843                        let cursor = if action.ignore_newlines {
12844                            movement::previous_word_start(map, selection.head())
12845                        } else {
12846                            movement::previous_word_start_or_newline(map, selection.head())
12847                        };
12848                        selection.set_head(cursor, SelectionGoal::None);
12849                    }
12850                });
12851            });
12852            this.insert("", window, cx);
12853        });
12854    }
12855
12856    pub fn delete_to_previous_subword_start(
12857        &mut self,
12858        _: &DeleteToPreviousSubwordStart,
12859        window: &mut Window,
12860        cx: &mut Context<Self>,
12861    ) {
12862        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12863        self.transact(window, cx, |this, window, cx| {
12864            this.select_autoclose_pair(window, cx);
12865            this.change_selections(Default::default(), window, cx, |s| {
12866                s.move_with(|map, selection| {
12867                    if selection.is_empty() {
12868                        let cursor = movement::previous_subword_start(map, selection.head());
12869                        selection.set_head(cursor, SelectionGoal::None);
12870                    }
12871                });
12872            });
12873            this.insert("", window, cx);
12874        });
12875    }
12876
12877    pub fn move_to_next_word_end(
12878        &mut self,
12879        _: &MoveToNextWordEnd,
12880        window: &mut Window,
12881        cx: &mut Context<Self>,
12882    ) {
12883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12884        self.change_selections(Default::default(), window, cx, |s| {
12885            s.move_cursors_with(|map, head, _| {
12886                (movement::next_word_end(map, head), SelectionGoal::None)
12887            });
12888        })
12889    }
12890
12891    pub fn move_to_next_subword_end(
12892        &mut self,
12893        _: &MoveToNextSubwordEnd,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_cursors_with(|map, head, _| {
12900                (movement::next_subword_end(map, head), SelectionGoal::None)
12901            });
12902        })
12903    }
12904
12905    pub fn select_to_next_word_end(
12906        &mut self,
12907        _: &SelectToNextWordEnd,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        self.change_selections(Default::default(), window, cx, |s| {
12913            s.move_heads_with(|map, head, _| {
12914                (movement::next_word_end(map, head), SelectionGoal::None)
12915            });
12916        })
12917    }
12918
12919    pub fn select_to_next_subword_end(
12920        &mut self,
12921        _: &SelectToNextSubwordEnd,
12922        window: &mut Window,
12923        cx: &mut Context<Self>,
12924    ) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        self.change_selections(Default::default(), window, cx, |s| {
12927            s.move_heads_with(|map, head, _| {
12928                (movement::next_subword_end(map, head), SelectionGoal::None)
12929            });
12930        })
12931    }
12932
12933    pub fn delete_to_next_word_end(
12934        &mut self,
12935        action: &DeleteToNextWordEnd,
12936        window: &mut Window,
12937        cx: &mut Context<Self>,
12938    ) {
12939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12940        self.transact(window, cx, |this, window, cx| {
12941            this.change_selections(Default::default(), window, cx, |s| {
12942                s.move_with(|map, selection| {
12943                    if selection.is_empty() {
12944                        let cursor = if action.ignore_newlines {
12945                            movement::next_word_end(map, selection.head())
12946                        } else {
12947                            movement::next_word_end_or_newline(map, selection.head())
12948                        };
12949                        selection.set_head(cursor, SelectionGoal::None);
12950                    }
12951                });
12952            });
12953            this.insert("", window, cx);
12954        });
12955    }
12956
12957    pub fn delete_to_next_subword_end(
12958        &mut self,
12959        _: &DeleteToNextSubwordEnd,
12960        window: &mut Window,
12961        cx: &mut Context<Self>,
12962    ) {
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12964        self.transact(window, cx, |this, window, cx| {
12965            this.change_selections(Default::default(), window, cx, |s| {
12966                s.move_with(|map, selection| {
12967                    if selection.is_empty() {
12968                        let cursor = movement::next_subword_end(map, selection.head());
12969                        selection.set_head(cursor, SelectionGoal::None);
12970                    }
12971                });
12972            });
12973            this.insert("", window, cx);
12974        });
12975    }
12976
12977    pub fn move_to_beginning_of_line(
12978        &mut self,
12979        action: &MoveToBeginningOfLine,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_cursors_with(|map, head, _| {
12986                (
12987                    movement::indented_line_beginning(
12988                        map,
12989                        head,
12990                        action.stop_at_soft_wraps,
12991                        action.stop_at_indent,
12992                    ),
12993                    SelectionGoal::None,
12994                )
12995            });
12996        })
12997    }
12998
12999    pub fn select_to_beginning_of_line(
13000        &mut self,
13001        action: &SelectToBeginningOfLine,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_heads_with(|map, head, _| {
13008                (
13009                    movement::indented_line_beginning(
13010                        map,
13011                        head,
13012                        action.stop_at_soft_wraps,
13013                        action.stop_at_indent,
13014                    ),
13015                    SelectionGoal::None,
13016                )
13017            });
13018        });
13019    }
13020
13021    pub fn delete_to_beginning_of_line(
13022        &mut self,
13023        action: &DeleteToBeginningOfLine,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13028        self.transact(window, cx, |this, window, cx| {
13029            this.change_selections(Default::default(), window, cx, |s| {
13030                s.move_with(|_, selection| {
13031                    selection.reversed = true;
13032                });
13033            });
13034
13035            this.select_to_beginning_of_line(
13036                &SelectToBeginningOfLine {
13037                    stop_at_soft_wraps: false,
13038                    stop_at_indent: action.stop_at_indent,
13039                },
13040                window,
13041                cx,
13042            );
13043            this.backspace(&Backspace, window, cx);
13044        });
13045    }
13046
13047    pub fn move_to_end_of_line(
13048        &mut self,
13049        action: &MoveToEndOfLine,
13050        window: &mut Window,
13051        cx: &mut Context<Self>,
13052    ) {
13053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13054        self.change_selections(Default::default(), window, cx, |s| {
13055            s.move_cursors_with(|map, head, _| {
13056                (
13057                    movement::line_end(map, head, action.stop_at_soft_wraps),
13058                    SelectionGoal::None,
13059                )
13060            });
13061        })
13062    }
13063
13064    pub fn select_to_end_of_line(
13065        &mut self,
13066        action: &SelectToEndOfLine,
13067        window: &mut Window,
13068        cx: &mut Context<Self>,
13069    ) {
13070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13071        self.change_selections(Default::default(), window, cx, |s| {
13072            s.move_heads_with(|map, head, _| {
13073                (
13074                    movement::line_end(map, head, action.stop_at_soft_wraps),
13075                    SelectionGoal::None,
13076                )
13077            });
13078        })
13079    }
13080
13081    pub fn delete_to_end_of_line(
13082        &mut self,
13083        _: &DeleteToEndOfLine,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13088        self.transact(window, cx, |this, window, cx| {
13089            this.select_to_end_of_line(
13090                &SelectToEndOfLine {
13091                    stop_at_soft_wraps: false,
13092                },
13093                window,
13094                cx,
13095            );
13096            this.delete(&Delete, window, cx);
13097        });
13098    }
13099
13100    pub fn cut_to_end_of_line(
13101        &mut self,
13102        _: &CutToEndOfLine,
13103        window: &mut Window,
13104        cx: &mut Context<Self>,
13105    ) {
13106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13107        self.transact(window, cx, |this, window, cx| {
13108            this.select_to_end_of_line(
13109                &SelectToEndOfLine {
13110                    stop_at_soft_wraps: false,
13111                },
13112                window,
13113                cx,
13114            );
13115            this.cut(&Cut, window, cx);
13116        });
13117    }
13118
13119    pub fn move_to_start_of_paragraph(
13120        &mut self,
13121        _: &MoveToStartOfParagraph,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13126            cx.propagate();
13127            return;
13128        }
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13130        self.change_selections(Default::default(), window, cx, |s| {
13131            s.move_with(|map, selection| {
13132                selection.collapse_to(
13133                    movement::start_of_paragraph(map, selection.head(), 1),
13134                    SelectionGoal::None,
13135                )
13136            });
13137        })
13138    }
13139
13140    pub fn move_to_end_of_paragraph(
13141        &mut self,
13142        _: &MoveToEndOfParagraph,
13143        window: &mut Window,
13144        cx: &mut Context<Self>,
13145    ) {
13146        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13147            cx.propagate();
13148            return;
13149        }
13150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13151        self.change_selections(Default::default(), window, cx, |s| {
13152            s.move_with(|map, selection| {
13153                selection.collapse_to(
13154                    movement::end_of_paragraph(map, selection.head(), 1),
13155                    SelectionGoal::None,
13156                )
13157            });
13158        })
13159    }
13160
13161    pub fn select_to_start_of_paragraph(
13162        &mut self,
13163        _: &SelectToStartOfParagraph,
13164        window: &mut Window,
13165        cx: &mut Context<Self>,
13166    ) {
13167        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13168            cx.propagate();
13169            return;
13170        }
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_heads_with(|map, head, _| {
13174                (
13175                    movement::start_of_paragraph(map, head, 1),
13176                    SelectionGoal::None,
13177                )
13178            });
13179        })
13180    }
13181
13182    pub fn select_to_end_of_paragraph(
13183        &mut self,
13184        _: &SelectToEndOfParagraph,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) {
13188        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13189            cx.propagate();
13190            return;
13191        }
13192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13193        self.change_selections(Default::default(), window, cx, |s| {
13194            s.move_heads_with(|map, head, _| {
13195                (
13196                    movement::end_of_paragraph(map, head, 1),
13197                    SelectionGoal::None,
13198                )
13199            });
13200        })
13201    }
13202
13203    pub fn move_to_start_of_excerpt(
13204        &mut self,
13205        _: &MoveToStartOfExcerpt,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13210            cx.propagate();
13211            return;
13212        }
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214        self.change_selections(Default::default(), window, cx, |s| {
13215            s.move_with(|map, selection| {
13216                selection.collapse_to(
13217                    movement::start_of_excerpt(
13218                        map,
13219                        selection.head(),
13220                        workspace::searchable::Direction::Prev,
13221                    ),
13222                    SelectionGoal::None,
13223                )
13224            });
13225        })
13226    }
13227
13228    pub fn move_to_start_of_next_excerpt(
13229        &mut self,
13230        _: &MoveToStartOfNextExcerpt,
13231        window: &mut Window,
13232        cx: &mut Context<Self>,
13233    ) {
13234        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13235            cx.propagate();
13236            return;
13237        }
13238
13239        self.change_selections(Default::default(), window, cx, |s| {
13240            s.move_with(|map, selection| {
13241                selection.collapse_to(
13242                    movement::start_of_excerpt(
13243                        map,
13244                        selection.head(),
13245                        workspace::searchable::Direction::Next,
13246                    ),
13247                    SelectionGoal::None,
13248                )
13249            });
13250        })
13251    }
13252
13253    pub fn move_to_end_of_excerpt(
13254        &mut self,
13255        _: &MoveToEndOfExcerpt,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13260            cx.propagate();
13261            return;
13262        }
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264        self.change_selections(Default::default(), window, cx, |s| {
13265            s.move_with(|map, selection| {
13266                selection.collapse_to(
13267                    movement::end_of_excerpt(
13268                        map,
13269                        selection.head(),
13270                        workspace::searchable::Direction::Next,
13271                    ),
13272                    SelectionGoal::None,
13273                )
13274            });
13275        })
13276    }
13277
13278    pub fn move_to_end_of_previous_excerpt(
13279        &mut self,
13280        _: &MoveToEndOfPreviousExcerpt,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13285            cx.propagate();
13286            return;
13287        }
13288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13289        self.change_selections(Default::default(), window, cx, |s| {
13290            s.move_with(|map, selection| {
13291                selection.collapse_to(
13292                    movement::end_of_excerpt(
13293                        map,
13294                        selection.head(),
13295                        workspace::searchable::Direction::Prev,
13296                    ),
13297                    SelectionGoal::None,
13298                )
13299            });
13300        })
13301    }
13302
13303    pub fn select_to_start_of_excerpt(
13304        &mut self,
13305        _: &SelectToStartOfExcerpt,
13306        window: &mut Window,
13307        cx: &mut Context<Self>,
13308    ) {
13309        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13310            cx.propagate();
13311            return;
13312        }
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13314        self.change_selections(Default::default(), window, cx, |s| {
13315            s.move_heads_with(|map, head, _| {
13316                (
13317                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13318                    SelectionGoal::None,
13319                )
13320            });
13321        })
13322    }
13323
13324    pub fn select_to_start_of_next_excerpt(
13325        &mut self,
13326        _: &SelectToStartOfNextExcerpt,
13327        window: &mut Window,
13328        cx: &mut Context<Self>,
13329    ) {
13330        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13331            cx.propagate();
13332            return;
13333        }
13334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13335        self.change_selections(Default::default(), window, cx, |s| {
13336            s.move_heads_with(|map, head, _| {
13337                (
13338                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13339                    SelectionGoal::None,
13340                )
13341            });
13342        })
13343    }
13344
13345    pub fn select_to_end_of_excerpt(
13346        &mut self,
13347        _: &SelectToEndOfExcerpt,
13348        window: &mut Window,
13349        cx: &mut Context<Self>,
13350    ) {
13351        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13352            cx.propagate();
13353            return;
13354        }
13355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13356        self.change_selections(Default::default(), window, cx, |s| {
13357            s.move_heads_with(|map, head, _| {
13358                (
13359                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13360                    SelectionGoal::None,
13361                )
13362            });
13363        })
13364    }
13365
13366    pub fn select_to_end_of_previous_excerpt(
13367        &mut self,
13368        _: &SelectToEndOfPreviousExcerpt,
13369        window: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13373            cx.propagate();
13374            return;
13375        }
13376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13377        self.change_selections(Default::default(), window, cx, |s| {
13378            s.move_heads_with(|map, head, _| {
13379                (
13380                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13381                    SelectionGoal::None,
13382                )
13383            });
13384        })
13385    }
13386
13387    pub fn move_to_beginning(
13388        &mut self,
13389        _: &MoveToBeginning,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13394            cx.propagate();
13395            return;
13396        }
13397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13398        self.change_selections(Default::default(), window, cx, |s| {
13399            s.select_ranges(vec![0..0]);
13400        });
13401    }
13402
13403    pub fn select_to_beginning(
13404        &mut self,
13405        _: &SelectToBeginning,
13406        window: &mut Window,
13407        cx: &mut Context<Self>,
13408    ) {
13409        let mut selection = self.selections.last::<Point>(cx);
13410        selection.set_head(Point::zero(), SelectionGoal::None);
13411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13412        self.change_selections(Default::default(), window, cx, |s| {
13413            s.select(vec![selection]);
13414        });
13415    }
13416
13417    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13418        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13419            cx.propagate();
13420            return;
13421        }
13422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13423        let cursor = self.buffer.read(cx).read(cx).len();
13424        self.change_selections(Default::default(), window, cx, |s| {
13425            s.select_ranges(vec![cursor..cursor])
13426        });
13427    }
13428
13429    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13430        self.nav_history = nav_history;
13431    }
13432
13433    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13434        self.nav_history.as_ref()
13435    }
13436
13437    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13438        self.push_to_nav_history(
13439            self.selections.newest_anchor().head(),
13440            None,
13441            false,
13442            true,
13443            cx,
13444        );
13445    }
13446
13447    fn push_to_nav_history(
13448        &mut self,
13449        cursor_anchor: Anchor,
13450        new_position: Option<Point>,
13451        is_deactivate: bool,
13452        always: bool,
13453        cx: &mut Context<Self>,
13454    ) {
13455        if let Some(nav_history) = self.nav_history.as_mut() {
13456            let buffer = self.buffer.read(cx).read(cx);
13457            let cursor_position = cursor_anchor.to_point(&buffer);
13458            let scroll_state = self.scroll_manager.anchor();
13459            let scroll_top_row = scroll_state.top_row(&buffer);
13460            drop(buffer);
13461
13462            if let Some(new_position) = new_position {
13463                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13464                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13465                    return;
13466                }
13467            }
13468
13469            nav_history.push(
13470                Some(NavigationData {
13471                    cursor_anchor,
13472                    cursor_position,
13473                    scroll_anchor: scroll_state,
13474                    scroll_top_row,
13475                }),
13476                cx,
13477            );
13478            cx.emit(EditorEvent::PushedToNavHistory {
13479                anchor: cursor_anchor,
13480                is_deactivate,
13481            })
13482        }
13483    }
13484
13485    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13487        let buffer = self.buffer.read(cx).snapshot(cx);
13488        let mut selection = self.selections.first::<usize>(cx);
13489        selection.set_head(buffer.len(), SelectionGoal::None);
13490        self.change_selections(Default::default(), window, cx, |s| {
13491            s.select(vec![selection]);
13492        });
13493    }
13494
13495    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13497        let end = self.buffer.read(cx).read(cx).len();
13498        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13499            s.select_ranges(vec![0..end]);
13500        });
13501    }
13502
13503    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13506        let mut selections = self.selections.all::<Point>(cx);
13507        let max_point = display_map.buffer_snapshot.max_point();
13508        for selection in &mut selections {
13509            let rows = selection.spanned_rows(true, &display_map);
13510            selection.start = Point::new(rows.start.0, 0);
13511            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13512            selection.reversed = false;
13513        }
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.select(selections);
13516        });
13517    }
13518
13519    pub fn split_selection_into_lines(
13520        &mut self,
13521        _: &SplitSelectionIntoLines,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        let selections = self
13526            .selections
13527            .all::<Point>(cx)
13528            .into_iter()
13529            .map(|selection| selection.start..selection.end)
13530            .collect::<Vec<_>>();
13531        self.unfold_ranges(&selections, true, true, cx);
13532
13533        let mut new_selection_ranges = Vec::new();
13534        {
13535            let buffer = self.buffer.read(cx).read(cx);
13536            for selection in selections {
13537                for row in selection.start.row..selection.end.row {
13538                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13539                    new_selection_ranges.push(cursor..cursor);
13540                }
13541
13542                let is_multiline_selection = selection.start.row != selection.end.row;
13543                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13544                // so this action feels more ergonomic when paired with other selection operations
13545                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13546                if !should_skip_last {
13547                    new_selection_ranges.push(selection.end..selection.end);
13548                }
13549            }
13550        }
13551        self.change_selections(Default::default(), window, cx, |s| {
13552            s.select_ranges(new_selection_ranges);
13553        });
13554    }
13555
13556    pub fn add_selection_above(
13557        &mut self,
13558        _: &AddSelectionAbove,
13559        window: &mut Window,
13560        cx: &mut Context<Self>,
13561    ) {
13562        self.add_selection(true, window, cx);
13563    }
13564
13565    pub fn add_selection_below(
13566        &mut self,
13567        _: &AddSelectionBelow,
13568        window: &mut Window,
13569        cx: &mut Context<Self>,
13570    ) {
13571        self.add_selection(false, window, cx);
13572    }
13573
13574    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13576
13577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13578        let all_selections = self.selections.all::<Point>(cx);
13579        let text_layout_details = self.text_layout_details(window);
13580
13581        let (mut columnar_selections, new_selections_to_columnarize) = {
13582            if let Some(state) = self.add_selections_state.as_ref() {
13583                let columnar_selection_ids: HashSet<_> = state
13584                    .groups
13585                    .iter()
13586                    .flat_map(|group| group.stack.iter())
13587                    .copied()
13588                    .collect();
13589
13590                all_selections
13591                    .into_iter()
13592                    .partition(|s| columnar_selection_ids.contains(&s.id))
13593            } else {
13594                (Vec::new(), all_selections)
13595            }
13596        };
13597
13598        let mut state = self
13599            .add_selections_state
13600            .take()
13601            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13602
13603        for selection in new_selections_to_columnarize {
13604            let range = selection.display_range(&display_map).sorted();
13605            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13606            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13607            let positions = start_x.min(end_x)..start_x.max(end_x);
13608            let mut stack = Vec::new();
13609            for row in range.start.row().0..=range.end.row().0 {
13610                if let Some(selection) = self.selections.build_columnar_selection(
13611                    &display_map,
13612                    DisplayRow(row),
13613                    &positions,
13614                    selection.reversed,
13615                    &text_layout_details,
13616                ) {
13617                    stack.push(selection.id);
13618                    columnar_selections.push(selection);
13619                }
13620            }
13621            if !stack.is_empty() {
13622                if above {
13623                    stack.reverse();
13624                }
13625                state.groups.push(AddSelectionsGroup { above, stack });
13626            }
13627        }
13628
13629        let mut final_selections = Vec::new();
13630        let end_row = if above {
13631            DisplayRow(0)
13632        } else {
13633            display_map.max_point().row()
13634        };
13635
13636        let mut last_added_item_per_group = HashMap::default();
13637        for group in state.groups.iter_mut() {
13638            if let Some(last_id) = group.stack.last() {
13639                last_added_item_per_group.insert(*last_id, group);
13640            }
13641        }
13642
13643        for selection in columnar_selections {
13644            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13645                if above == group.above {
13646                    let range = selection.display_range(&display_map).sorted();
13647                    debug_assert_eq!(range.start.row(), range.end.row());
13648                    let mut row = range.start.row();
13649                    let positions =
13650                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13651                            px(start)..px(end)
13652                        } else {
13653                            let start_x =
13654                                display_map.x_for_display_point(range.start, &text_layout_details);
13655                            let end_x =
13656                                display_map.x_for_display_point(range.end, &text_layout_details);
13657                            start_x.min(end_x)..start_x.max(end_x)
13658                        };
13659
13660                    let mut maybe_new_selection = None;
13661                    while row != end_row {
13662                        if above {
13663                            row.0 -= 1;
13664                        } else {
13665                            row.0 += 1;
13666                        }
13667                        if let Some(new_selection) = self.selections.build_columnar_selection(
13668                            &display_map,
13669                            row,
13670                            &positions,
13671                            selection.reversed,
13672                            &text_layout_details,
13673                        ) {
13674                            maybe_new_selection = Some(new_selection);
13675                            break;
13676                        }
13677                    }
13678
13679                    if let Some(new_selection) = maybe_new_selection {
13680                        group.stack.push(new_selection.id);
13681                        if above {
13682                            final_selections.push(new_selection);
13683                            final_selections.push(selection);
13684                        } else {
13685                            final_selections.push(selection);
13686                            final_selections.push(new_selection);
13687                        }
13688                    } else {
13689                        final_selections.push(selection);
13690                    }
13691                } else {
13692                    group.stack.pop();
13693                }
13694            } else {
13695                final_selections.push(selection);
13696            }
13697        }
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.select(final_selections);
13701        });
13702
13703        let final_selection_ids: HashSet<_> = self
13704            .selections
13705            .all::<Point>(cx)
13706            .iter()
13707            .map(|s| s.id)
13708            .collect();
13709        state.groups.retain_mut(|group| {
13710            // selections might get merged above so we remove invalid items from stacks
13711            group.stack.retain(|id| final_selection_ids.contains(id));
13712
13713            // single selection in stack can be treated as initial state
13714            group.stack.len() > 1
13715        });
13716
13717        if !state.groups.is_empty() {
13718            self.add_selections_state = Some(state);
13719        }
13720    }
13721
13722    fn select_match_ranges(
13723        &mut self,
13724        range: Range<usize>,
13725        reversed: bool,
13726        replace_newest: bool,
13727        auto_scroll: Option<Autoscroll>,
13728        window: &mut Window,
13729        cx: &mut Context<Editor>,
13730    ) {
13731        self.unfold_ranges(
13732            std::slice::from_ref(&range),
13733            false,
13734            auto_scroll.is_some(),
13735            cx,
13736        );
13737        let effects = if let Some(scroll) = auto_scroll {
13738            SelectionEffects::scroll(scroll)
13739        } else {
13740            SelectionEffects::no_scroll()
13741        };
13742        self.change_selections(effects, window, cx, |s| {
13743            if replace_newest {
13744                s.delete(s.newest_anchor().id);
13745            }
13746            if reversed {
13747                s.insert_range(range.end..range.start);
13748            } else {
13749                s.insert_range(range);
13750            }
13751        });
13752    }
13753
13754    pub fn select_next_match_internal(
13755        &mut self,
13756        display_map: &DisplaySnapshot,
13757        replace_newest: bool,
13758        autoscroll: Option<Autoscroll>,
13759        window: &mut Window,
13760        cx: &mut Context<Self>,
13761    ) -> Result<()> {
13762        let buffer = &display_map.buffer_snapshot;
13763        let mut selections = self.selections.all::<usize>(cx);
13764        if let Some(mut select_next_state) = self.select_next_state.take() {
13765            let query = &select_next_state.query;
13766            if !select_next_state.done {
13767                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13768                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13769                let mut next_selected_range = None;
13770
13771                let bytes_after_last_selection =
13772                    buffer.bytes_in_range(last_selection.end..buffer.len());
13773                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13774                let query_matches = query
13775                    .stream_find_iter(bytes_after_last_selection)
13776                    .map(|result| (last_selection.end, result))
13777                    .chain(
13778                        query
13779                            .stream_find_iter(bytes_before_first_selection)
13780                            .map(|result| (0, result)),
13781                    );
13782
13783                for (start_offset, query_match) in query_matches {
13784                    let query_match = query_match.unwrap(); // can only fail due to I/O
13785                    let offset_range =
13786                        start_offset + query_match.start()..start_offset + query_match.end();
13787
13788                    if !select_next_state.wordwise
13789                        || (!buffer.is_inside_word(offset_range.start, false)
13790                            && !buffer.is_inside_word(offset_range.end, false))
13791                    {
13792                        // TODO: This is n^2, because we might check all the selections
13793                        if !selections
13794                            .iter()
13795                            .any(|selection| selection.range().overlaps(&offset_range))
13796                        {
13797                            next_selected_range = Some(offset_range);
13798                            break;
13799                        }
13800                    }
13801                }
13802
13803                if let Some(next_selected_range) = next_selected_range {
13804                    self.select_match_ranges(
13805                        next_selected_range,
13806                        last_selection.reversed,
13807                        replace_newest,
13808                        autoscroll,
13809                        window,
13810                        cx,
13811                    );
13812                } else {
13813                    select_next_state.done = true;
13814                }
13815            }
13816
13817            self.select_next_state = Some(select_next_state);
13818        } else {
13819            let mut only_carets = true;
13820            let mut same_text_selected = true;
13821            let mut selected_text = None;
13822
13823            let mut selections_iter = selections.iter().peekable();
13824            while let Some(selection) = selections_iter.next() {
13825                if selection.start != selection.end {
13826                    only_carets = false;
13827                }
13828
13829                if same_text_selected {
13830                    if selected_text.is_none() {
13831                        selected_text =
13832                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13833                    }
13834
13835                    if let Some(next_selection) = selections_iter.peek() {
13836                        if next_selection.range().len() == selection.range().len() {
13837                            let next_selected_text = buffer
13838                                .text_for_range(next_selection.range())
13839                                .collect::<String>();
13840                            if Some(next_selected_text) != selected_text {
13841                                same_text_selected = false;
13842                                selected_text = None;
13843                            }
13844                        } else {
13845                            same_text_selected = false;
13846                            selected_text = None;
13847                        }
13848                    }
13849                }
13850            }
13851
13852            if only_carets {
13853                for selection in &mut selections {
13854                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13855                    selection.start = word_range.start;
13856                    selection.end = word_range.end;
13857                    selection.goal = SelectionGoal::None;
13858                    selection.reversed = false;
13859                    self.select_match_ranges(
13860                        selection.start..selection.end,
13861                        selection.reversed,
13862                        replace_newest,
13863                        autoscroll,
13864                        window,
13865                        cx,
13866                    );
13867                }
13868
13869                if selections.len() == 1 {
13870                    let selection = selections
13871                        .last()
13872                        .expect("ensured that there's only one selection");
13873                    let query = buffer
13874                        .text_for_range(selection.start..selection.end)
13875                        .collect::<String>();
13876                    let is_empty = query.is_empty();
13877                    let select_state = SelectNextState {
13878                        query: AhoCorasick::new(&[query])?,
13879                        wordwise: true,
13880                        done: is_empty,
13881                    };
13882                    self.select_next_state = Some(select_state);
13883                } else {
13884                    self.select_next_state = None;
13885                }
13886            } else if let Some(selected_text) = selected_text {
13887                self.select_next_state = Some(SelectNextState {
13888                    query: AhoCorasick::new(&[selected_text])?,
13889                    wordwise: false,
13890                    done: false,
13891                });
13892                self.select_next_match_internal(
13893                    display_map,
13894                    replace_newest,
13895                    autoscroll,
13896                    window,
13897                    cx,
13898                )?;
13899            }
13900        }
13901        Ok(())
13902    }
13903
13904    pub fn select_all_matches(
13905        &mut self,
13906        _action: &SelectAllMatches,
13907        window: &mut Window,
13908        cx: &mut Context<Self>,
13909    ) -> Result<()> {
13910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13911
13912        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13913
13914        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13915        let Some(select_next_state) = self.select_next_state.as_mut() else {
13916            return Ok(());
13917        };
13918        if select_next_state.done {
13919            return Ok(());
13920        }
13921
13922        let mut new_selections = Vec::new();
13923
13924        let reversed = self.selections.oldest::<usize>(cx).reversed;
13925        let buffer = &display_map.buffer_snapshot;
13926        let query_matches = select_next_state
13927            .query
13928            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13929
13930        for query_match in query_matches.into_iter() {
13931            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13932            let offset_range = if reversed {
13933                query_match.end()..query_match.start()
13934            } else {
13935                query_match.start()..query_match.end()
13936            };
13937
13938            if !select_next_state.wordwise
13939                || (!buffer.is_inside_word(offset_range.start, false)
13940                    && !buffer.is_inside_word(offset_range.end, false))
13941            {
13942                new_selections.push(offset_range.start..offset_range.end);
13943            }
13944        }
13945
13946        select_next_state.done = true;
13947
13948        if new_selections.is_empty() {
13949            log::error!("bug: new_selections is empty in select_all_matches");
13950            return Ok(());
13951        }
13952
13953        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13954        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13955            selections.select_ranges(new_selections)
13956        });
13957
13958        Ok(())
13959    }
13960
13961    pub fn select_next(
13962        &mut self,
13963        action: &SelectNext,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) -> Result<()> {
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13969        self.select_next_match_internal(
13970            &display_map,
13971            action.replace_newest,
13972            Some(Autoscroll::newest()),
13973            window,
13974            cx,
13975        )?;
13976        Ok(())
13977    }
13978
13979    pub fn select_previous(
13980        &mut self,
13981        action: &SelectPrevious,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) -> Result<()> {
13985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13986        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13987        let buffer = &display_map.buffer_snapshot;
13988        let mut selections = self.selections.all::<usize>(cx);
13989        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13990            let query = &select_prev_state.query;
13991            if !select_prev_state.done {
13992                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13993                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13994                let mut next_selected_range = None;
13995                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13996                let bytes_before_last_selection =
13997                    buffer.reversed_bytes_in_range(0..last_selection.start);
13998                let bytes_after_first_selection =
13999                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14000                let query_matches = query
14001                    .stream_find_iter(bytes_before_last_selection)
14002                    .map(|result| (last_selection.start, result))
14003                    .chain(
14004                        query
14005                            .stream_find_iter(bytes_after_first_selection)
14006                            .map(|result| (buffer.len(), result)),
14007                    );
14008                for (end_offset, query_match) in query_matches {
14009                    let query_match = query_match.unwrap(); // can only fail due to I/O
14010                    let offset_range =
14011                        end_offset - query_match.end()..end_offset - query_match.start();
14012
14013                    if !select_prev_state.wordwise
14014                        || (!buffer.is_inside_word(offset_range.start, false)
14015                            && !buffer.is_inside_word(offset_range.end, false))
14016                    {
14017                        next_selected_range = Some(offset_range);
14018                        break;
14019                    }
14020                }
14021
14022                if let Some(next_selected_range) = next_selected_range {
14023                    self.select_match_ranges(
14024                        next_selected_range,
14025                        last_selection.reversed,
14026                        action.replace_newest,
14027                        Some(Autoscroll::newest()),
14028                        window,
14029                        cx,
14030                    );
14031                } else {
14032                    select_prev_state.done = true;
14033                }
14034            }
14035
14036            self.select_prev_state = Some(select_prev_state);
14037        } else {
14038            let mut only_carets = true;
14039            let mut same_text_selected = true;
14040            let mut selected_text = None;
14041
14042            let mut selections_iter = selections.iter().peekable();
14043            while let Some(selection) = selections_iter.next() {
14044                if selection.start != selection.end {
14045                    only_carets = false;
14046                }
14047
14048                if same_text_selected {
14049                    if selected_text.is_none() {
14050                        selected_text =
14051                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14052                    }
14053
14054                    if let Some(next_selection) = selections_iter.peek() {
14055                        if next_selection.range().len() == selection.range().len() {
14056                            let next_selected_text = buffer
14057                                .text_for_range(next_selection.range())
14058                                .collect::<String>();
14059                            if Some(next_selected_text) != selected_text {
14060                                same_text_selected = false;
14061                                selected_text = None;
14062                            }
14063                        } else {
14064                            same_text_selected = false;
14065                            selected_text = None;
14066                        }
14067                    }
14068                }
14069            }
14070
14071            if only_carets {
14072                for selection in &mut selections {
14073                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14074                    selection.start = word_range.start;
14075                    selection.end = word_range.end;
14076                    selection.goal = SelectionGoal::None;
14077                    selection.reversed = false;
14078                    self.select_match_ranges(
14079                        selection.start..selection.end,
14080                        selection.reversed,
14081                        action.replace_newest,
14082                        Some(Autoscroll::newest()),
14083                        window,
14084                        cx,
14085                    );
14086                }
14087                if selections.len() == 1 {
14088                    let selection = selections
14089                        .last()
14090                        .expect("ensured that there's only one selection");
14091                    let query = buffer
14092                        .text_for_range(selection.start..selection.end)
14093                        .collect::<String>();
14094                    let is_empty = query.is_empty();
14095                    let select_state = SelectNextState {
14096                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14097                        wordwise: true,
14098                        done: is_empty,
14099                    };
14100                    self.select_prev_state = Some(select_state);
14101                } else {
14102                    self.select_prev_state = None;
14103                }
14104            } else if let Some(selected_text) = selected_text {
14105                self.select_prev_state = Some(SelectNextState {
14106                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14107                    wordwise: false,
14108                    done: false,
14109                });
14110                self.select_previous(action, window, cx)?;
14111            }
14112        }
14113        Ok(())
14114    }
14115
14116    pub fn find_next_match(
14117        &mut self,
14118        _: &FindNextMatch,
14119        window: &mut Window,
14120        cx: &mut Context<Self>,
14121    ) -> Result<()> {
14122        let selections = self.selections.disjoint_anchors();
14123        match selections.first() {
14124            Some(first) if selections.len() >= 2 => {
14125                self.change_selections(Default::default(), window, cx, |s| {
14126                    s.select_ranges([first.range()]);
14127                });
14128            }
14129            _ => self.select_next(
14130                &SelectNext {
14131                    replace_newest: true,
14132                },
14133                window,
14134                cx,
14135            )?,
14136        }
14137        Ok(())
14138    }
14139
14140    pub fn find_previous_match(
14141        &mut self,
14142        _: &FindPreviousMatch,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) -> Result<()> {
14146        let selections = self.selections.disjoint_anchors();
14147        match selections.last() {
14148            Some(last) if selections.len() >= 2 => {
14149                self.change_selections(Default::default(), window, cx, |s| {
14150                    s.select_ranges([last.range()]);
14151                });
14152            }
14153            _ => self.select_previous(
14154                &SelectPrevious {
14155                    replace_newest: true,
14156                },
14157                window,
14158                cx,
14159            )?,
14160        }
14161        Ok(())
14162    }
14163
14164    pub fn toggle_comments(
14165        &mut self,
14166        action: &ToggleComments,
14167        window: &mut Window,
14168        cx: &mut Context<Self>,
14169    ) {
14170        if self.read_only(cx) {
14171            return;
14172        }
14173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14174        let text_layout_details = &self.text_layout_details(window);
14175        self.transact(window, cx, |this, window, cx| {
14176            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14177            let mut edits = Vec::new();
14178            let mut selection_edit_ranges = Vec::new();
14179            let mut last_toggled_row = None;
14180            let snapshot = this.buffer.read(cx).read(cx);
14181            let empty_str: Arc<str> = Arc::default();
14182            let mut suffixes_inserted = Vec::new();
14183            let ignore_indent = action.ignore_indent;
14184
14185            fn comment_prefix_range(
14186                snapshot: &MultiBufferSnapshot,
14187                row: MultiBufferRow,
14188                comment_prefix: &str,
14189                comment_prefix_whitespace: &str,
14190                ignore_indent: bool,
14191            ) -> Range<Point> {
14192                let indent_size = if ignore_indent {
14193                    0
14194                } else {
14195                    snapshot.indent_size_for_line(row).len
14196                };
14197
14198                let start = Point::new(row.0, indent_size);
14199
14200                let mut line_bytes = snapshot
14201                    .bytes_in_range(start..snapshot.max_point())
14202                    .flatten()
14203                    .copied();
14204
14205                // If this line currently begins with the line comment prefix, then record
14206                // the range containing the prefix.
14207                if line_bytes
14208                    .by_ref()
14209                    .take(comment_prefix.len())
14210                    .eq(comment_prefix.bytes())
14211                {
14212                    // Include any whitespace that matches the comment prefix.
14213                    let matching_whitespace_len = line_bytes
14214                        .zip(comment_prefix_whitespace.bytes())
14215                        .take_while(|(a, b)| a == b)
14216                        .count() as u32;
14217                    let end = Point::new(
14218                        start.row,
14219                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14220                    );
14221                    start..end
14222                } else {
14223                    start..start
14224                }
14225            }
14226
14227            fn comment_suffix_range(
14228                snapshot: &MultiBufferSnapshot,
14229                row: MultiBufferRow,
14230                comment_suffix: &str,
14231                comment_suffix_has_leading_space: bool,
14232            ) -> Range<Point> {
14233                let end = Point::new(row.0, snapshot.line_len(row));
14234                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14235
14236                let mut line_end_bytes = snapshot
14237                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14238                    .flatten()
14239                    .copied();
14240
14241                let leading_space_len = if suffix_start_column > 0
14242                    && line_end_bytes.next() == Some(b' ')
14243                    && comment_suffix_has_leading_space
14244                {
14245                    1
14246                } else {
14247                    0
14248                };
14249
14250                // If this line currently begins with the line comment prefix, then record
14251                // the range containing the prefix.
14252                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14253                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14254                    start..end
14255                } else {
14256                    end..end
14257                }
14258            }
14259
14260            // TODO: Handle selections that cross excerpts
14261            for selection in &mut selections {
14262                let start_column = snapshot
14263                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14264                    .len;
14265                let language = if let Some(language) =
14266                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14267                {
14268                    language
14269                } else {
14270                    continue;
14271                };
14272
14273                selection_edit_ranges.clear();
14274
14275                // If multiple selections contain a given row, avoid processing that
14276                // row more than once.
14277                let mut start_row = MultiBufferRow(selection.start.row);
14278                if last_toggled_row == Some(start_row) {
14279                    start_row = start_row.next_row();
14280                }
14281                let end_row =
14282                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14283                        MultiBufferRow(selection.end.row - 1)
14284                    } else {
14285                        MultiBufferRow(selection.end.row)
14286                    };
14287                last_toggled_row = Some(end_row);
14288
14289                if start_row > end_row {
14290                    continue;
14291                }
14292
14293                // If the language has line comments, toggle those.
14294                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14295
14296                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14297                if ignore_indent {
14298                    full_comment_prefixes = full_comment_prefixes
14299                        .into_iter()
14300                        .map(|s| Arc::from(s.trim_end()))
14301                        .collect();
14302                }
14303
14304                if !full_comment_prefixes.is_empty() {
14305                    let first_prefix = full_comment_prefixes
14306                        .first()
14307                        .expect("prefixes is non-empty");
14308                    let prefix_trimmed_lengths = full_comment_prefixes
14309                        .iter()
14310                        .map(|p| p.trim_end_matches(' ').len())
14311                        .collect::<SmallVec<[usize; 4]>>();
14312
14313                    let mut all_selection_lines_are_comments = true;
14314
14315                    for row in start_row.0..=end_row.0 {
14316                        let row = MultiBufferRow(row);
14317                        if start_row < end_row && snapshot.is_line_blank(row) {
14318                            continue;
14319                        }
14320
14321                        let prefix_range = full_comment_prefixes
14322                            .iter()
14323                            .zip(prefix_trimmed_lengths.iter().copied())
14324                            .map(|(prefix, trimmed_prefix_len)| {
14325                                comment_prefix_range(
14326                                    snapshot.deref(),
14327                                    row,
14328                                    &prefix[..trimmed_prefix_len],
14329                                    &prefix[trimmed_prefix_len..],
14330                                    ignore_indent,
14331                                )
14332                            })
14333                            .max_by_key(|range| range.end.column - range.start.column)
14334                            .expect("prefixes is non-empty");
14335
14336                        if prefix_range.is_empty() {
14337                            all_selection_lines_are_comments = false;
14338                        }
14339
14340                        selection_edit_ranges.push(prefix_range);
14341                    }
14342
14343                    if all_selection_lines_are_comments {
14344                        edits.extend(
14345                            selection_edit_ranges
14346                                .iter()
14347                                .cloned()
14348                                .map(|range| (range, empty_str.clone())),
14349                        );
14350                    } else {
14351                        let min_column = selection_edit_ranges
14352                            .iter()
14353                            .map(|range| range.start.column)
14354                            .min()
14355                            .unwrap_or(0);
14356                        edits.extend(selection_edit_ranges.iter().map(|range| {
14357                            let position = Point::new(range.start.row, min_column);
14358                            (position..position, first_prefix.clone())
14359                        }));
14360                    }
14361                } else if let Some(BlockCommentConfig {
14362                    start: full_comment_prefix,
14363                    end: comment_suffix,
14364                    ..
14365                }) = language.block_comment()
14366                {
14367                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14368                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14369                    let prefix_range = comment_prefix_range(
14370                        snapshot.deref(),
14371                        start_row,
14372                        comment_prefix,
14373                        comment_prefix_whitespace,
14374                        ignore_indent,
14375                    );
14376                    let suffix_range = comment_suffix_range(
14377                        snapshot.deref(),
14378                        end_row,
14379                        comment_suffix.trim_start_matches(' '),
14380                        comment_suffix.starts_with(' '),
14381                    );
14382
14383                    if prefix_range.is_empty() || suffix_range.is_empty() {
14384                        edits.push((
14385                            prefix_range.start..prefix_range.start,
14386                            full_comment_prefix.clone(),
14387                        ));
14388                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14389                        suffixes_inserted.push((end_row, comment_suffix.len()));
14390                    } else {
14391                        edits.push((prefix_range, empty_str.clone()));
14392                        edits.push((suffix_range, empty_str.clone()));
14393                    }
14394                } else {
14395                    continue;
14396                }
14397            }
14398
14399            drop(snapshot);
14400            this.buffer.update(cx, |buffer, cx| {
14401                buffer.edit(edits, None, cx);
14402            });
14403
14404            // Adjust selections so that they end before any comment suffixes that
14405            // were inserted.
14406            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14407            let mut selections = this.selections.all::<Point>(cx);
14408            let snapshot = this.buffer.read(cx).read(cx);
14409            for selection in &mut selections {
14410                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14411                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14412                        Ordering::Less => {
14413                            suffixes_inserted.next();
14414                            continue;
14415                        }
14416                        Ordering::Greater => break,
14417                        Ordering::Equal => {
14418                            if selection.end.column == snapshot.line_len(row) {
14419                                if selection.is_empty() {
14420                                    selection.start.column -= suffix_len as u32;
14421                                }
14422                                selection.end.column -= suffix_len as u32;
14423                            }
14424                            break;
14425                        }
14426                    }
14427                }
14428            }
14429
14430            drop(snapshot);
14431            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14432
14433            let selections = this.selections.all::<Point>(cx);
14434            let selections_on_single_row = selections.windows(2).all(|selections| {
14435                selections[0].start.row == selections[1].start.row
14436                    && selections[0].end.row == selections[1].end.row
14437                    && selections[0].start.row == selections[0].end.row
14438            });
14439            let selections_selecting = selections
14440                .iter()
14441                .any(|selection| selection.start != selection.end);
14442            let advance_downwards = action.advance_downwards
14443                && selections_on_single_row
14444                && !selections_selecting
14445                && !matches!(this.mode, EditorMode::SingleLine { .. });
14446
14447            if advance_downwards {
14448                let snapshot = this.buffer.read(cx).snapshot(cx);
14449
14450                this.change_selections(Default::default(), window, cx, |s| {
14451                    s.move_cursors_with(|display_snapshot, display_point, _| {
14452                        let mut point = display_point.to_point(display_snapshot);
14453                        point.row += 1;
14454                        point = snapshot.clip_point(point, Bias::Left);
14455                        let display_point = point.to_display_point(display_snapshot);
14456                        let goal = SelectionGoal::HorizontalPosition(
14457                            display_snapshot
14458                                .x_for_display_point(display_point, text_layout_details)
14459                                .into(),
14460                        );
14461                        (display_point, goal)
14462                    })
14463                });
14464            }
14465        });
14466    }
14467
14468    pub fn select_enclosing_symbol(
14469        &mut self,
14470        _: &SelectEnclosingSymbol,
14471        window: &mut Window,
14472        cx: &mut Context<Self>,
14473    ) {
14474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14475
14476        let buffer = self.buffer.read(cx).snapshot(cx);
14477        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14478
14479        fn update_selection(
14480            selection: &Selection<usize>,
14481            buffer_snap: &MultiBufferSnapshot,
14482        ) -> Option<Selection<usize>> {
14483            let cursor = selection.head();
14484            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14485            for symbol in symbols.iter().rev() {
14486                let start = symbol.range.start.to_offset(buffer_snap);
14487                let end = symbol.range.end.to_offset(buffer_snap);
14488                let new_range = start..end;
14489                if start < selection.start || end > selection.end {
14490                    return Some(Selection {
14491                        id: selection.id,
14492                        start: new_range.start,
14493                        end: new_range.end,
14494                        goal: SelectionGoal::None,
14495                        reversed: selection.reversed,
14496                    });
14497                }
14498            }
14499            None
14500        }
14501
14502        let mut selected_larger_symbol = false;
14503        let new_selections = old_selections
14504            .iter()
14505            .map(|selection| match update_selection(selection, &buffer) {
14506                Some(new_selection) => {
14507                    if new_selection.range() != selection.range() {
14508                        selected_larger_symbol = true;
14509                    }
14510                    new_selection
14511                }
14512                None => selection.clone(),
14513            })
14514            .collect::<Vec<_>>();
14515
14516        if selected_larger_symbol {
14517            self.change_selections(Default::default(), window, cx, |s| {
14518                s.select(new_selections);
14519            });
14520        }
14521    }
14522
14523    pub fn select_larger_syntax_node(
14524        &mut self,
14525        _: &SelectLargerSyntaxNode,
14526        window: &mut Window,
14527        cx: &mut Context<Self>,
14528    ) {
14529        let Some(visible_row_count) = self.visible_row_count() else {
14530            return;
14531        };
14532        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14533        if old_selections.is_empty() {
14534            return;
14535        }
14536
14537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14538
14539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14540        let buffer = self.buffer.read(cx).snapshot(cx);
14541
14542        let mut selected_larger_node = false;
14543        let mut new_selections = old_selections
14544            .iter()
14545            .map(|selection| {
14546                let old_range = selection.start..selection.end;
14547
14548                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14549                    // manually select word at selection
14550                    if ["string_content", "inline"].contains(&node.kind()) {
14551                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14552                        // ignore if word is already selected
14553                        if !word_range.is_empty() && old_range != word_range {
14554                            let (last_word_range, _) =
14555                                buffer.surrounding_word(old_range.end, false);
14556                            // only select word if start and end point belongs to same word
14557                            if word_range == last_word_range {
14558                                selected_larger_node = true;
14559                                return Selection {
14560                                    id: selection.id,
14561                                    start: word_range.start,
14562                                    end: word_range.end,
14563                                    goal: SelectionGoal::None,
14564                                    reversed: selection.reversed,
14565                                };
14566                            }
14567                        }
14568                    }
14569                }
14570
14571                let mut new_range = old_range.clone();
14572                while let Some((_node, containing_range)) =
14573                    buffer.syntax_ancestor(new_range.clone())
14574                {
14575                    new_range = match containing_range {
14576                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14577                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14578                    };
14579                    if !display_map.intersects_fold(new_range.start)
14580                        && !display_map.intersects_fold(new_range.end)
14581                    {
14582                        break;
14583                    }
14584                }
14585
14586                selected_larger_node |= new_range != old_range;
14587                Selection {
14588                    id: selection.id,
14589                    start: new_range.start,
14590                    end: new_range.end,
14591                    goal: SelectionGoal::None,
14592                    reversed: selection.reversed,
14593                }
14594            })
14595            .collect::<Vec<_>>();
14596
14597        if !selected_larger_node {
14598            return; // don't put this call in the history
14599        }
14600
14601        // scroll based on transformation done to the last selection created by the user
14602        let (last_old, last_new) = old_selections
14603            .last()
14604            .zip(new_selections.last().cloned())
14605            .expect("old_selections isn't empty");
14606
14607        // revert selection
14608        let is_selection_reversed = {
14609            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14610            new_selections.last_mut().expect("checked above").reversed =
14611                should_newest_selection_be_reversed;
14612            should_newest_selection_be_reversed
14613        };
14614
14615        if selected_larger_node {
14616            self.select_syntax_node_history.disable_clearing = true;
14617            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14618                s.select(new_selections.clone());
14619            });
14620            self.select_syntax_node_history.disable_clearing = false;
14621        }
14622
14623        let start_row = last_new.start.to_display_point(&display_map).row().0;
14624        let end_row = last_new.end.to_display_point(&display_map).row().0;
14625        let selection_height = end_row - start_row + 1;
14626        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14627
14628        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14629        let scroll_behavior = if fits_on_the_screen {
14630            self.request_autoscroll(Autoscroll::fit(), cx);
14631            SelectSyntaxNodeScrollBehavior::FitSelection
14632        } else if is_selection_reversed {
14633            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14634            SelectSyntaxNodeScrollBehavior::CursorTop
14635        } else {
14636            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14637            SelectSyntaxNodeScrollBehavior::CursorBottom
14638        };
14639
14640        self.select_syntax_node_history.push((
14641            old_selections,
14642            scroll_behavior,
14643            is_selection_reversed,
14644        ));
14645    }
14646
14647    pub fn select_smaller_syntax_node(
14648        &mut self,
14649        _: &SelectSmallerSyntaxNode,
14650        window: &mut Window,
14651        cx: &mut Context<Self>,
14652    ) {
14653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14654
14655        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14656            self.select_syntax_node_history.pop()
14657        {
14658            if let Some(selection) = selections.last_mut() {
14659                selection.reversed = is_selection_reversed;
14660            }
14661
14662            self.select_syntax_node_history.disable_clearing = true;
14663            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14664                s.select(selections.to_vec());
14665            });
14666            self.select_syntax_node_history.disable_clearing = false;
14667
14668            match scroll_behavior {
14669                SelectSyntaxNodeScrollBehavior::CursorTop => {
14670                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14671                }
14672                SelectSyntaxNodeScrollBehavior::FitSelection => {
14673                    self.request_autoscroll(Autoscroll::fit(), cx);
14674                }
14675                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14676                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14677                }
14678            }
14679        }
14680    }
14681
14682    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14683        if !EditorSettings::get_global(cx).gutter.runnables {
14684            self.clear_tasks();
14685            return Task::ready(());
14686        }
14687        let project = self.project.as_ref().map(Entity::downgrade);
14688        let task_sources = self.lsp_task_sources(cx);
14689        let multi_buffer = self.buffer.downgrade();
14690        cx.spawn_in(window, async move |editor, cx| {
14691            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14692            let Some(project) = project.and_then(|p| p.upgrade()) else {
14693                return;
14694            };
14695            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14696                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14697            }) else {
14698                return;
14699            };
14700
14701            let hide_runnables = project
14702                .update(cx, |project, cx| {
14703                    // Do not display any test indicators in non-dev server remote projects.
14704                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14705                })
14706                .unwrap_or(true);
14707            if hide_runnables {
14708                return;
14709            }
14710            let new_rows =
14711                cx.background_spawn({
14712                    let snapshot = display_snapshot.clone();
14713                    async move {
14714                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14715                    }
14716                })
14717                    .await;
14718            let Ok(lsp_tasks) =
14719                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14720            else {
14721                return;
14722            };
14723            let lsp_tasks = lsp_tasks.await;
14724
14725            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14726                lsp_tasks
14727                    .into_iter()
14728                    .flat_map(|(kind, tasks)| {
14729                        tasks.into_iter().filter_map(move |(location, task)| {
14730                            Some((kind.clone(), location?, task))
14731                        })
14732                    })
14733                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14734                        let buffer = location.target.buffer;
14735                        let buffer_snapshot = buffer.read(cx).snapshot();
14736                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14737                            |(excerpt_id, snapshot, _)| {
14738                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14739                                    display_snapshot
14740                                        .buffer_snapshot
14741                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14742                                } else {
14743                                    None
14744                                }
14745                            },
14746                        );
14747                        if let Some(offset) = offset {
14748                            let task_buffer_range =
14749                                location.target.range.to_point(&buffer_snapshot);
14750                            let context_buffer_range =
14751                                task_buffer_range.to_offset(&buffer_snapshot);
14752                            let context_range = BufferOffset(context_buffer_range.start)
14753                                ..BufferOffset(context_buffer_range.end);
14754
14755                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14756                                .or_insert_with(|| RunnableTasks {
14757                                    templates: Vec::new(),
14758                                    offset,
14759                                    column: task_buffer_range.start.column,
14760                                    extra_variables: HashMap::default(),
14761                                    context_range,
14762                                })
14763                                .templates
14764                                .push((kind, task.original_task().clone()));
14765                        }
14766
14767                        acc
14768                    })
14769            }) else {
14770                return;
14771            };
14772
14773            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14774                buffer.language_settings(cx).tasks.prefer_lsp
14775            }) else {
14776                return;
14777            };
14778
14779            let rows = Self::runnable_rows(
14780                project,
14781                display_snapshot,
14782                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14783                new_rows,
14784                cx.clone(),
14785            )
14786            .await;
14787            editor
14788                .update(cx, |editor, _| {
14789                    editor.clear_tasks();
14790                    for (key, mut value) in rows {
14791                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14792                            value.templates.extend(lsp_tasks.templates);
14793                        }
14794
14795                        editor.insert_tasks(key, value);
14796                    }
14797                    for (key, value) in lsp_tasks_by_rows {
14798                        editor.insert_tasks(key, value);
14799                    }
14800                })
14801                .ok();
14802        })
14803    }
14804    fn fetch_runnable_ranges(
14805        snapshot: &DisplaySnapshot,
14806        range: Range<Anchor>,
14807    ) -> Vec<language::RunnableRange> {
14808        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14809    }
14810
14811    fn runnable_rows(
14812        project: Entity<Project>,
14813        snapshot: DisplaySnapshot,
14814        prefer_lsp: bool,
14815        runnable_ranges: Vec<RunnableRange>,
14816        cx: AsyncWindowContext,
14817    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14818        cx.spawn(async move |cx| {
14819            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14820            for mut runnable in runnable_ranges {
14821                let Some(tasks) = cx
14822                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14823                    .ok()
14824                else {
14825                    continue;
14826                };
14827                let mut tasks = tasks.await;
14828
14829                if prefer_lsp {
14830                    tasks.retain(|(task_kind, _)| {
14831                        !matches!(task_kind, TaskSourceKind::Language { .. })
14832                    });
14833                }
14834                if tasks.is_empty() {
14835                    continue;
14836                }
14837
14838                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14839                let Some(row) = snapshot
14840                    .buffer_snapshot
14841                    .buffer_line_for_row(MultiBufferRow(point.row))
14842                    .map(|(_, range)| range.start.row)
14843                else {
14844                    continue;
14845                };
14846
14847                let context_range =
14848                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14849                runnable_rows.push((
14850                    (runnable.buffer_id, row),
14851                    RunnableTasks {
14852                        templates: tasks,
14853                        offset: snapshot
14854                            .buffer_snapshot
14855                            .anchor_before(runnable.run_range.start),
14856                        context_range,
14857                        column: point.column,
14858                        extra_variables: runnable.extra_captures,
14859                    },
14860                ));
14861            }
14862            runnable_rows
14863        })
14864    }
14865
14866    fn templates_with_tags(
14867        project: &Entity<Project>,
14868        runnable: &mut Runnable,
14869        cx: &mut App,
14870    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14871        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14872            let (worktree_id, file) = project
14873                .buffer_for_id(runnable.buffer, cx)
14874                .and_then(|buffer| buffer.read(cx).file())
14875                .map(|file| (file.worktree_id(cx), file.clone()))
14876                .unzip();
14877
14878            (
14879                project.task_store().read(cx).task_inventory().cloned(),
14880                worktree_id,
14881                file,
14882            )
14883        });
14884
14885        let tags = mem::take(&mut runnable.tags);
14886        let language = runnable.language.clone();
14887        cx.spawn(async move |cx| {
14888            let mut templates_with_tags = Vec::new();
14889            if let Some(inventory) = inventory {
14890                for RunnableTag(tag) in tags {
14891                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14892                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14893                    }) else {
14894                        return templates_with_tags;
14895                    };
14896                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14897                        move |(_, template)| {
14898                            template.tags.iter().any(|source_tag| source_tag == &tag)
14899                        },
14900                    ));
14901                }
14902            }
14903            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14904
14905            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14906                // Strongest source wins; if we have worktree tag binding, prefer that to
14907                // global and language bindings;
14908                // if we have a global binding, prefer that to language binding.
14909                let first_mismatch = templates_with_tags
14910                    .iter()
14911                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14912                if let Some(index) = first_mismatch {
14913                    templates_with_tags.truncate(index);
14914                }
14915            }
14916
14917            templates_with_tags
14918        })
14919    }
14920
14921    pub fn move_to_enclosing_bracket(
14922        &mut self,
14923        _: &MoveToEnclosingBracket,
14924        window: &mut Window,
14925        cx: &mut Context<Self>,
14926    ) {
14927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14928        self.change_selections(Default::default(), window, cx, |s| {
14929            s.move_offsets_with(|snapshot, selection| {
14930                let Some(enclosing_bracket_ranges) =
14931                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14932                else {
14933                    return;
14934                };
14935
14936                let mut best_length = usize::MAX;
14937                let mut best_inside = false;
14938                let mut best_in_bracket_range = false;
14939                let mut best_destination = None;
14940                for (open, close) in enclosing_bracket_ranges {
14941                    let close = close.to_inclusive();
14942                    let length = close.end() - open.start;
14943                    let inside = selection.start >= open.end && selection.end <= *close.start();
14944                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14945                        || close.contains(&selection.head());
14946
14947                    // If best is next to a bracket and current isn't, skip
14948                    if !in_bracket_range && best_in_bracket_range {
14949                        continue;
14950                    }
14951
14952                    // Prefer smaller lengths unless best is inside and current isn't
14953                    if length > best_length && (best_inside || !inside) {
14954                        continue;
14955                    }
14956
14957                    best_length = length;
14958                    best_inside = inside;
14959                    best_in_bracket_range = in_bracket_range;
14960                    best_destination = Some(
14961                        if close.contains(&selection.start) && close.contains(&selection.end) {
14962                            if inside { open.end } else { open.start }
14963                        } else if inside {
14964                            *close.start()
14965                        } else {
14966                            *close.end()
14967                        },
14968                    );
14969                }
14970
14971                if let Some(destination) = best_destination {
14972                    selection.collapse_to(destination, SelectionGoal::None);
14973                }
14974            })
14975        });
14976    }
14977
14978    pub fn undo_selection(
14979        &mut self,
14980        _: &UndoSelection,
14981        window: &mut Window,
14982        cx: &mut Context<Self>,
14983    ) {
14984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14985        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14986            self.selection_history.mode = SelectionHistoryMode::Undoing;
14987            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14988                this.end_selection(window, cx);
14989                this.change_selections(
14990                    SelectionEffects::scroll(Autoscroll::newest()),
14991                    window,
14992                    cx,
14993                    |s| s.select_anchors(entry.selections.to_vec()),
14994                );
14995            });
14996            self.selection_history.mode = SelectionHistoryMode::Normal;
14997
14998            self.select_next_state = entry.select_next_state;
14999            self.select_prev_state = entry.select_prev_state;
15000            self.add_selections_state = entry.add_selections_state;
15001        }
15002    }
15003
15004    pub fn redo_selection(
15005        &mut self,
15006        _: &RedoSelection,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) {
15010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15011        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15012            self.selection_history.mode = SelectionHistoryMode::Redoing;
15013            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15014                this.end_selection(window, cx);
15015                this.change_selections(
15016                    SelectionEffects::scroll(Autoscroll::newest()),
15017                    window,
15018                    cx,
15019                    |s| s.select_anchors(entry.selections.to_vec()),
15020                );
15021            });
15022            self.selection_history.mode = SelectionHistoryMode::Normal;
15023
15024            self.select_next_state = entry.select_next_state;
15025            self.select_prev_state = entry.select_prev_state;
15026            self.add_selections_state = entry.add_selections_state;
15027        }
15028    }
15029
15030    pub fn expand_excerpts(
15031        &mut self,
15032        action: &ExpandExcerpts,
15033        _: &mut Window,
15034        cx: &mut Context<Self>,
15035    ) {
15036        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15037    }
15038
15039    pub fn expand_excerpts_down(
15040        &mut self,
15041        action: &ExpandExcerptsDown,
15042        _: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) {
15045        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15046    }
15047
15048    pub fn expand_excerpts_up(
15049        &mut self,
15050        action: &ExpandExcerptsUp,
15051        _: &mut Window,
15052        cx: &mut Context<Self>,
15053    ) {
15054        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15055    }
15056
15057    pub fn expand_excerpts_for_direction(
15058        &mut self,
15059        lines: u32,
15060        direction: ExpandExcerptDirection,
15061
15062        cx: &mut Context<Self>,
15063    ) {
15064        let selections = self.selections.disjoint_anchors();
15065
15066        let lines = if lines == 0 {
15067            EditorSettings::get_global(cx).expand_excerpt_lines
15068        } else {
15069            lines
15070        };
15071
15072        self.buffer.update(cx, |buffer, cx| {
15073            let snapshot = buffer.snapshot(cx);
15074            let mut excerpt_ids = selections
15075                .iter()
15076                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15077                .collect::<Vec<_>>();
15078            excerpt_ids.sort();
15079            excerpt_ids.dedup();
15080            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15081        })
15082    }
15083
15084    pub fn expand_excerpt(
15085        &mut self,
15086        excerpt: ExcerptId,
15087        direction: ExpandExcerptDirection,
15088        window: &mut Window,
15089        cx: &mut Context<Self>,
15090    ) {
15091        let current_scroll_position = self.scroll_position(cx);
15092        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15093        let mut should_scroll_up = false;
15094
15095        if direction == ExpandExcerptDirection::Down {
15096            let multi_buffer = self.buffer.read(cx);
15097            let snapshot = multi_buffer.snapshot(cx);
15098            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15099                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15100                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15101                        let buffer_snapshot = buffer.read(cx).snapshot();
15102                        let excerpt_end_row =
15103                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15104                        let last_row = buffer_snapshot.max_point().row;
15105                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15106                        should_scroll_up = lines_below >= lines_to_expand;
15107                    }
15108                }
15109            }
15110        }
15111
15112        self.buffer.update(cx, |buffer, cx| {
15113            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15114        });
15115
15116        if should_scroll_up {
15117            let new_scroll_position =
15118                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15119            self.set_scroll_position(new_scroll_position, window, cx);
15120        }
15121    }
15122
15123    pub fn go_to_singleton_buffer_point(
15124        &mut self,
15125        point: Point,
15126        window: &mut Window,
15127        cx: &mut Context<Self>,
15128    ) {
15129        self.go_to_singleton_buffer_range(point..point, window, cx);
15130    }
15131
15132    pub fn go_to_singleton_buffer_range(
15133        &mut self,
15134        range: Range<Point>,
15135        window: &mut Window,
15136        cx: &mut Context<Self>,
15137    ) {
15138        let multibuffer = self.buffer().read(cx);
15139        let Some(buffer) = multibuffer.as_singleton() else {
15140            return;
15141        };
15142        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15143            return;
15144        };
15145        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15146            return;
15147        };
15148        self.change_selections(
15149            SelectionEffects::default().nav_history(true),
15150            window,
15151            cx,
15152            |s| s.select_anchor_ranges([start..end]),
15153        );
15154    }
15155
15156    pub fn go_to_diagnostic(
15157        &mut self,
15158        action: &GoToDiagnostic,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) {
15162        if !self.diagnostics_enabled() {
15163            return;
15164        }
15165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15166        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15167    }
15168
15169    pub fn go_to_prev_diagnostic(
15170        &mut self,
15171        action: &GoToPreviousDiagnostic,
15172        window: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        if !self.diagnostics_enabled() {
15176            return;
15177        }
15178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15179        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15180    }
15181
15182    pub fn go_to_diagnostic_impl(
15183        &mut self,
15184        direction: Direction,
15185        severity: GoToDiagnosticSeverityFilter,
15186        window: &mut Window,
15187        cx: &mut Context<Self>,
15188    ) {
15189        let buffer = self.buffer.read(cx).snapshot(cx);
15190        let selection = self.selections.newest::<usize>(cx);
15191
15192        let mut active_group_id = None;
15193        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15194            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15195                active_group_id = Some(active_group.group_id);
15196            }
15197        }
15198
15199        fn filtered(
15200            snapshot: EditorSnapshot,
15201            severity: GoToDiagnosticSeverityFilter,
15202            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15203        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15204            diagnostics
15205                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15206                .filter(|entry| entry.range.start != entry.range.end)
15207                .filter(|entry| !entry.diagnostic.is_unnecessary)
15208                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15209        }
15210
15211        let snapshot = self.snapshot(window, cx);
15212        let before = filtered(
15213            snapshot.clone(),
15214            severity,
15215            buffer
15216                .diagnostics_in_range(0..selection.start)
15217                .filter(|entry| entry.range.start <= selection.start),
15218        );
15219        let after = filtered(
15220            snapshot,
15221            severity,
15222            buffer
15223                .diagnostics_in_range(selection.start..buffer.len())
15224                .filter(|entry| entry.range.start >= selection.start),
15225        );
15226
15227        let mut found: Option<DiagnosticEntry<usize>> = None;
15228        if direction == Direction::Prev {
15229            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15230            {
15231                for diagnostic in prev_diagnostics.into_iter().rev() {
15232                    if diagnostic.range.start != selection.start
15233                        || active_group_id
15234                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15235                    {
15236                        found = Some(diagnostic);
15237                        break 'outer;
15238                    }
15239                }
15240            }
15241        } else {
15242            for diagnostic in after.chain(before) {
15243                if diagnostic.range.start != selection.start
15244                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15245                {
15246                    found = Some(diagnostic);
15247                    break;
15248                }
15249            }
15250        }
15251        let Some(next_diagnostic) = found else {
15252            return;
15253        };
15254
15255        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15256            return;
15257        };
15258        self.change_selections(Default::default(), window, cx, |s| {
15259            s.select_ranges(vec![
15260                next_diagnostic.range.start..next_diagnostic.range.start,
15261            ])
15262        });
15263        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15264        self.refresh_inline_completion(false, true, window, cx);
15265    }
15266
15267    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15269        let snapshot = self.snapshot(window, cx);
15270        let selection = self.selections.newest::<Point>(cx);
15271        self.go_to_hunk_before_or_after_position(
15272            &snapshot,
15273            selection.head(),
15274            Direction::Next,
15275            window,
15276            cx,
15277        );
15278    }
15279
15280    pub fn go_to_hunk_before_or_after_position(
15281        &mut self,
15282        snapshot: &EditorSnapshot,
15283        position: Point,
15284        direction: Direction,
15285        window: &mut Window,
15286        cx: &mut Context<Editor>,
15287    ) {
15288        let row = if direction == Direction::Next {
15289            self.hunk_after_position(snapshot, position)
15290                .map(|hunk| hunk.row_range.start)
15291        } else {
15292            self.hunk_before_position(snapshot, position)
15293        };
15294
15295        if let Some(row) = row {
15296            let destination = Point::new(row.0, 0);
15297            let autoscroll = Autoscroll::center();
15298
15299            self.unfold_ranges(&[destination..destination], false, false, cx);
15300            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15301                s.select_ranges([destination..destination]);
15302            });
15303        }
15304    }
15305
15306    fn hunk_after_position(
15307        &mut self,
15308        snapshot: &EditorSnapshot,
15309        position: Point,
15310    ) -> Option<MultiBufferDiffHunk> {
15311        snapshot
15312            .buffer_snapshot
15313            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15314            .find(|hunk| hunk.row_range.start.0 > position.row)
15315            .or_else(|| {
15316                snapshot
15317                    .buffer_snapshot
15318                    .diff_hunks_in_range(Point::zero()..position)
15319                    .find(|hunk| hunk.row_range.end.0 < position.row)
15320            })
15321    }
15322
15323    fn go_to_prev_hunk(
15324        &mut self,
15325        _: &GoToPreviousHunk,
15326        window: &mut Window,
15327        cx: &mut Context<Self>,
15328    ) {
15329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15330        let snapshot = self.snapshot(window, cx);
15331        let selection = self.selections.newest::<Point>(cx);
15332        self.go_to_hunk_before_or_after_position(
15333            &snapshot,
15334            selection.head(),
15335            Direction::Prev,
15336            window,
15337            cx,
15338        );
15339    }
15340
15341    fn hunk_before_position(
15342        &mut self,
15343        snapshot: &EditorSnapshot,
15344        position: Point,
15345    ) -> Option<MultiBufferRow> {
15346        snapshot
15347            .buffer_snapshot
15348            .diff_hunk_before(position)
15349            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15350    }
15351
15352    fn go_to_next_change(
15353        &mut self,
15354        _: &GoToNextChange,
15355        window: &mut Window,
15356        cx: &mut Context<Self>,
15357    ) {
15358        if let Some(selections) = self
15359            .change_list
15360            .next_change(1, Direction::Next)
15361            .map(|s| s.to_vec())
15362        {
15363            self.change_selections(Default::default(), window, cx, |s| {
15364                let map = s.display_map();
15365                s.select_display_ranges(selections.iter().map(|a| {
15366                    let point = a.to_display_point(&map);
15367                    point..point
15368                }))
15369            })
15370        }
15371    }
15372
15373    fn go_to_previous_change(
15374        &mut self,
15375        _: &GoToPreviousChange,
15376        window: &mut Window,
15377        cx: &mut Context<Self>,
15378    ) {
15379        if let Some(selections) = self
15380            .change_list
15381            .next_change(1, Direction::Prev)
15382            .map(|s| s.to_vec())
15383        {
15384            self.change_selections(Default::default(), window, cx, |s| {
15385                let map = s.display_map();
15386                s.select_display_ranges(selections.iter().map(|a| {
15387                    let point = a.to_display_point(&map);
15388                    point..point
15389                }))
15390            })
15391        }
15392    }
15393
15394    fn go_to_line<T: 'static>(
15395        &mut self,
15396        position: Anchor,
15397        highlight_color: Option<Hsla>,
15398        window: &mut Window,
15399        cx: &mut Context<Self>,
15400    ) {
15401        let snapshot = self.snapshot(window, cx).display_snapshot;
15402        let position = position.to_point(&snapshot.buffer_snapshot);
15403        let start = snapshot
15404            .buffer_snapshot
15405            .clip_point(Point::new(position.row, 0), Bias::Left);
15406        let end = start + Point::new(1, 0);
15407        let start = snapshot.buffer_snapshot.anchor_before(start);
15408        let end = snapshot.buffer_snapshot.anchor_before(end);
15409
15410        self.highlight_rows::<T>(
15411            start..end,
15412            highlight_color
15413                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15414            Default::default(),
15415            cx,
15416        );
15417
15418        if self.buffer.read(cx).is_singleton() {
15419            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15420        }
15421    }
15422
15423    pub fn go_to_definition(
15424        &mut self,
15425        _: &GoToDefinition,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) -> Task<Result<Navigated>> {
15429        let definition =
15430            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15431        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15432        cx.spawn_in(window, async move |editor, cx| {
15433            if definition.await? == Navigated::Yes {
15434                return Ok(Navigated::Yes);
15435            }
15436            match fallback_strategy {
15437                GoToDefinitionFallback::None => Ok(Navigated::No),
15438                GoToDefinitionFallback::FindAllReferences => {
15439                    match editor.update_in(cx, |editor, window, cx| {
15440                        editor.find_all_references(&FindAllReferences, window, cx)
15441                    })? {
15442                        Some(references) => references.await,
15443                        None => Ok(Navigated::No),
15444                    }
15445                }
15446            }
15447        })
15448    }
15449
15450    pub fn go_to_declaration(
15451        &mut self,
15452        _: &GoToDeclaration,
15453        window: &mut Window,
15454        cx: &mut Context<Self>,
15455    ) -> Task<Result<Navigated>> {
15456        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15457    }
15458
15459    pub fn go_to_declaration_split(
15460        &mut self,
15461        _: &GoToDeclaration,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) -> Task<Result<Navigated>> {
15465        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15466    }
15467
15468    pub fn go_to_implementation(
15469        &mut self,
15470        _: &GoToImplementation,
15471        window: &mut Window,
15472        cx: &mut Context<Self>,
15473    ) -> Task<Result<Navigated>> {
15474        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15475    }
15476
15477    pub fn go_to_implementation_split(
15478        &mut self,
15479        _: &GoToImplementationSplit,
15480        window: &mut Window,
15481        cx: &mut Context<Self>,
15482    ) -> Task<Result<Navigated>> {
15483        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15484    }
15485
15486    pub fn go_to_type_definition(
15487        &mut self,
15488        _: &GoToTypeDefinition,
15489        window: &mut Window,
15490        cx: &mut Context<Self>,
15491    ) -> Task<Result<Navigated>> {
15492        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15493    }
15494
15495    pub fn go_to_definition_split(
15496        &mut self,
15497        _: &GoToDefinitionSplit,
15498        window: &mut Window,
15499        cx: &mut Context<Self>,
15500    ) -> Task<Result<Navigated>> {
15501        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15502    }
15503
15504    pub fn go_to_type_definition_split(
15505        &mut self,
15506        _: &GoToTypeDefinitionSplit,
15507        window: &mut Window,
15508        cx: &mut Context<Self>,
15509    ) -> Task<Result<Navigated>> {
15510        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15511    }
15512
15513    fn go_to_definition_of_kind(
15514        &mut self,
15515        kind: GotoDefinitionKind,
15516        split: bool,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) -> Task<Result<Navigated>> {
15520        let Some(provider) = self.semantics_provider.clone() else {
15521            return Task::ready(Ok(Navigated::No));
15522        };
15523        let head = self.selections.newest::<usize>(cx).head();
15524        let buffer = self.buffer.read(cx);
15525        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15526            text_anchor
15527        } else {
15528            return Task::ready(Ok(Navigated::No));
15529        };
15530
15531        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15532            return Task::ready(Ok(Navigated::No));
15533        };
15534
15535        cx.spawn_in(window, async move |editor, cx| {
15536            let definitions = definitions.await?;
15537            let navigated = editor
15538                .update_in(cx, |editor, window, cx| {
15539                    editor.navigate_to_hover_links(
15540                        Some(kind),
15541                        definitions
15542                            .into_iter()
15543                            .filter(|location| {
15544                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15545                            })
15546                            .map(HoverLink::Text)
15547                            .collect::<Vec<_>>(),
15548                        split,
15549                        window,
15550                        cx,
15551                    )
15552                })?
15553                .await?;
15554            anyhow::Ok(navigated)
15555        })
15556    }
15557
15558    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15559        let selection = self.selections.newest_anchor();
15560        let head = selection.head();
15561        let tail = selection.tail();
15562
15563        let Some((buffer, start_position)) =
15564            self.buffer.read(cx).text_anchor_for_position(head, cx)
15565        else {
15566            return;
15567        };
15568
15569        let end_position = if head != tail {
15570            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15571                return;
15572            };
15573            Some(pos)
15574        } else {
15575            None
15576        };
15577
15578        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15579            let url = if let Some(end_pos) = end_position {
15580                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15581            } else {
15582                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15583            };
15584
15585            if let Some(url) = url {
15586                editor.update(cx, |_, cx| {
15587                    cx.open_url(&url);
15588                })
15589            } else {
15590                Ok(())
15591            }
15592        });
15593
15594        url_finder.detach();
15595    }
15596
15597    pub fn open_selected_filename(
15598        &mut self,
15599        _: &OpenSelectedFilename,
15600        window: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) {
15603        let Some(workspace) = self.workspace() else {
15604            return;
15605        };
15606
15607        let position = self.selections.newest_anchor().head();
15608
15609        let Some((buffer, buffer_position)) =
15610            self.buffer.read(cx).text_anchor_for_position(position, cx)
15611        else {
15612            return;
15613        };
15614
15615        let project = self.project.clone();
15616
15617        cx.spawn_in(window, async move |_, cx| {
15618            let result = find_file(&buffer, project, buffer_position, cx).await;
15619
15620            if let Some((_, path)) = result {
15621                workspace
15622                    .update_in(cx, |workspace, window, cx| {
15623                        workspace.open_resolved_path(path, window, cx)
15624                    })?
15625                    .await?;
15626            }
15627            anyhow::Ok(())
15628        })
15629        .detach();
15630    }
15631
15632    pub(crate) fn navigate_to_hover_links(
15633        &mut self,
15634        kind: Option<GotoDefinitionKind>,
15635        mut definitions: Vec<HoverLink>,
15636        split: bool,
15637        window: &mut Window,
15638        cx: &mut Context<Editor>,
15639    ) -> Task<Result<Navigated>> {
15640        // If there is one definition, just open it directly
15641        if definitions.len() == 1 {
15642            let definition = definitions.pop().unwrap();
15643
15644            enum TargetTaskResult {
15645                Location(Option<Location>),
15646                AlreadyNavigated,
15647            }
15648
15649            let target_task = match definition {
15650                HoverLink::Text(link) => {
15651                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15652                }
15653                HoverLink::InlayHint(lsp_location, server_id) => {
15654                    let computation =
15655                        self.compute_target_location(lsp_location, server_id, window, cx);
15656                    cx.background_spawn(async move {
15657                        let location = computation.await?;
15658                        Ok(TargetTaskResult::Location(location))
15659                    })
15660                }
15661                HoverLink::Url(url) => {
15662                    cx.open_url(&url);
15663                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15664                }
15665                HoverLink::File(path) => {
15666                    if let Some(workspace) = self.workspace() {
15667                        cx.spawn_in(window, async move |_, cx| {
15668                            workspace
15669                                .update_in(cx, |workspace, window, cx| {
15670                                    workspace.open_resolved_path(path, window, cx)
15671                                })?
15672                                .await
15673                                .map(|_| TargetTaskResult::AlreadyNavigated)
15674                        })
15675                    } else {
15676                        Task::ready(Ok(TargetTaskResult::Location(None)))
15677                    }
15678                }
15679            };
15680            cx.spawn_in(window, async move |editor, cx| {
15681                let target = match target_task.await.context("target resolution task")? {
15682                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15683                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15684                    TargetTaskResult::Location(Some(target)) => target,
15685                };
15686
15687                editor.update_in(cx, |editor, window, cx| {
15688                    let Some(workspace) = editor.workspace() else {
15689                        return Navigated::No;
15690                    };
15691                    let pane = workspace.read(cx).active_pane().clone();
15692
15693                    let range = target.range.to_point(target.buffer.read(cx));
15694                    let range = editor.range_for_match(&range);
15695                    let range = collapse_multiline_range(range);
15696
15697                    if !split
15698                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15699                    {
15700                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15701                    } else {
15702                        window.defer(cx, move |window, cx| {
15703                            let target_editor: Entity<Self> =
15704                                workspace.update(cx, |workspace, cx| {
15705                                    let pane = if split {
15706                                        workspace.adjacent_pane(window, cx)
15707                                    } else {
15708                                        workspace.active_pane().clone()
15709                                    };
15710
15711                                    workspace.open_project_item(
15712                                        pane,
15713                                        target.buffer.clone(),
15714                                        true,
15715                                        true,
15716                                        window,
15717                                        cx,
15718                                    )
15719                                });
15720                            target_editor.update(cx, |target_editor, cx| {
15721                                // When selecting a definition in a different buffer, disable the nav history
15722                                // to avoid creating a history entry at the previous cursor location.
15723                                pane.update(cx, |pane, _| pane.disable_history());
15724                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15725                                pane.update(cx, |pane, _| pane.enable_history());
15726                            });
15727                        });
15728                    }
15729                    Navigated::Yes
15730                })
15731            })
15732        } else if !definitions.is_empty() {
15733            cx.spawn_in(window, async move |editor, cx| {
15734                let (title, location_tasks, workspace) = editor
15735                    .update_in(cx, |editor, window, cx| {
15736                        let tab_kind = match kind {
15737                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15738                            _ => "Definitions",
15739                        };
15740                        let title = definitions
15741                            .iter()
15742                            .find_map(|definition| match definition {
15743                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15744                                    let buffer = origin.buffer.read(cx);
15745                                    format!(
15746                                        "{} for {}",
15747                                        tab_kind,
15748                                        buffer
15749                                            .text_for_range(origin.range.clone())
15750                                            .collect::<String>()
15751                                    )
15752                                }),
15753                                HoverLink::InlayHint(_, _) => None,
15754                                HoverLink::Url(_) => None,
15755                                HoverLink::File(_) => None,
15756                            })
15757                            .unwrap_or(tab_kind.to_string());
15758                        let location_tasks = definitions
15759                            .into_iter()
15760                            .map(|definition| match definition {
15761                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15762                                HoverLink::InlayHint(lsp_location, server_id) => editor
15763                                    .compute_target_location(lsp_location, server_id, window, cx),
15764                                HoverLink::Url(_) => Task::ready(Ok(None)),
15765                                HoverLink::File(_) => Task::ready(Ok(None)),
15766                            })
15767                            .collect::<Vec<_>>();
15768                        (title, location_tasks, editor.workspace().clone())
15769                    })
15770                    .context("location tasks preparation")?;
15771
15772                let locations: Vec<Location> = future::join_all(location_tasks)
15773                    .await
15774                    .into_iter()
15775                    .filter_map(|location| location.transpose())
15776                    .collect::<Result<_>>()
15777                    .context("location tasks")?;
15778
15779                if locations.is_empty() {
15780                    return Ok(Navigated::No);
15781                }
15782
15783                let Some(workspace) = workspace else {
15784                    return Ok(Navigated::No);
15785                };
15786
15787                let opened = workspace
15788                    .update_in(cx, |workspace, window, cx| {
15789                        Self::open_locations_in_multibuffer(
15790                            workspace,
15791                            locations,
15792                            title,
15793                            split,
15794                            MultibufferSelectionMode::First,
15795                            window,
15796                            cx,
15797                        )
15798                    })
15799                    .ok();
15800
15801                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15802            })
15803        } else {
15804            Task::ready(Ok(Navigated::No))
15805        }
15806    }
15807
15808    fn compute_target_location(
15809        &self,
15810        lsp_location: lsp::Location,
15811        server_id: LanguageServerId,
15812        window: &mut Window,
15813        cx: &mut Context<Self>,
15814    ) -> Task<anyhow::Result<Option<Location>>> {
15815        let Some(project) = self.project.clone() else {
15816            return Task::ready(Ok(None));
15817        };
15818
15819        cx.spawn_in(window, async move |editor, cx| {
15820            let location_task = editor.update(cx, |_, cx| {
15821                project.update(cx, |project, cx| {
15822                    let language_server_name = project
15823                        .language_server_statuses(cx)
15824                        .find(|(id, _)| server_id == *id)
15825                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15826                    language_server_name.map(|language_server_name| {
15827                        project.open_local_buffer_via_lsp(
15828                            lsp_location.uri.clone(),
15829                            server_id,
15830                            language_server_name,
15831                            cx,
15832                        )
15833                    })
15834                })
15835            })?;
15836            let location = match location_task {
15837                Some(task) => Some({
15838                    let target_buffer_handle = task.await.context("open local buffer")?;
15839                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15840                        let target_start = target_buffer
15841                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15842                        let target_end = target_buffer
15843                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15844                        target_buffer.anchor_after(target_start)
15845                            ..target_buffer.anchor_before(target_end)
15846                    })?;
15847                    Location {
15848                        buffer: target_buffer_handle,
15849                        range,
15850                    }
15851                }),
15852                None => None,
15853            };
15854            Ok(location)
15855        })
15856    }
15857
15858    pub fn find_all_references(
15859        &mut self,
15860        _: &FindAllReferences,
15861        window: &mut Window,
15862        cx: &mut Context<Self>,
15863    ) -> Option<Task<Result<Navigated>>> {
15864        let selection = self.selections.newest::<usize>(cx);
15865        let multi_buffer = self.buffer.read(cx);
15866        let head = selection.head();
15867
15868        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15869        let head_anchor = multi_buffer_snapshot.anchor_at(
15870            head,
15871            if head < selection.tail() {
15872                Bias::Right
15873            } else {
15874                Bias::Left
15875            },
15876        );
15877
15878        match self
15879            .find_all_references_task_sources
15880            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15881        {
15882            Ok(_) => {
15883                log::info!(
15884                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15885                );
15886                return None;
15887            }
15888            Err(i) => {
15889                self.find_all_references_task_sources.insert(i, head_anchor);
15890            }
15891        }
15892
15893        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15894        let workspace = self.workspace()?;
15895        let project = workspace.read(cx).project().clone();
15896        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15897        Some(cx.spawn_in(window, async move |editor, cx| {
15898            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15899                if let Ok(i) = editor
15900                    .find_all_references_task_sources
15901                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15902                {
15903                    editor.find_all_references_task_sources.remove(i);
15904                }
15905            });
15906
15907            let locations = references.await?;
15908            if locations.is_empty() {
15909                return anyhow::Ok(Navigated::No);
15910            }
15911
15912            workspace.update_in(cx, |workspace, window, cx| {
15913                let title = locations
15914                    .first()
15915                    .as_ref()
15916                    .map(|location| {
15917                        let buffer = location.buffer.read(cx);
15918                        format!(
15919                            "References to `{}`",
15920                            buffer
15921                                .text_for_range(location.range.clone())
15922                                .collect::<String>()
15923                        )
15924                    })
15925                    .unwrap();
15926                Self::open_locations_in_multibuffer(
15927                    workspace,
15928                    locations,
15929                    title,
15930                    false,
15931                    MultibufferSelectionMode::First,
15932                    window,
15933                    cx,
15934                );
15935                Navigated::Yes
15936            })
15937        }))
15938    }
15939
15940    /// Opens a multibuffer with the given project locations in it
15941    pub fn open_locations_in_multibuffer(
15942        workspace: &mut Workspace,
15943        mut locations: Vec<Location>,
15944        title: String,
15945        split: bool,
15946        multibuffer_selection_mode: MultibufferSelectionMode,
15947        window: &mut Window,
15948        cx: &mut Context<Workspace>,
15949    ) {
15950        if locations.is_empty() {
15951            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15952            return;
15953        }
15954
15955        // If there are multiple definitions, open them in a multibuffer
15956        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15957        let mut locations = locations.into_iter().peekable();
15958        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15959        let capability = workspace.project().read(cx).capability();
15960
15961        let excerpt_buffer = cx.new(|cx| {
15962            let mut multibuffer = MultiBuffer::new(capability);
15963            while let Some(location) = locations.next() {
15964                let buffer = location.buffer.read(cx);
15965                let mut ranges_for_buffer = Vec::new();
15966                let range = location.range.to_point(buffer);
15967                ranges_for_buffer.push(range.clone());
15968
15969                while let Some(next_location) = locations.peek() {
15970                    if next_location.buffer == location.buffer {
15971                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15972                        locations.next();
15973                    } else {
15974                        break;
15975                    }
15976                }
15977
15978                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15979                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15980                    PathKey::for_buffer(&location.buffer, cx),
15981                    location.buffer.clone(),
15982                    ranges_for_buffer,
15983                    DEFAULT_MULTIBUFFER_CONTEXT,
15984                    cx,
15985                );
15986                ranges.extend(new_ranges)
15987            }
15988
15989            multibuffer.with_title(title)
15990        });
15991
15992        let editor = cx.new(|cx| {
15993            Editor::for_multibuffer(
15994                excerpt_buffer,
15995                Some(workspace.project().clone()),
15996                window,
15997                cx,
15998            )
15999        });
16000        editor.update(cx, |editor, cx| {
16001            match multibuffer_selection_mode {
16002                MultibufferSelectionMode::First => {
16003                    if let Some(first_range) = ranges.first() {
16004                        editor.change_selections(
16005                            SelectionEffects::no_scroll(),
16006                            window,
16007                            cx,
16008                            |selections| {
16009                                selections.clear_disjoint();
16010                                selections
16011                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16012                            },
16013                        );
16014                    }
16015                    editor.highlight_background::<Self>(
16016                        &ranges,
16017                        |theme| theme.colors().editor_highlighted_line_background,
16018                        cx,
16019                    );
16020                }
16021                MultibufferSelectionMode::All => {
16022                    editor.change_selections(
16023                        SelectionEffects::no_scroll(),
16024                        window,
16025                        cx,
16026                        |selections| {
16027                            selections.clear_disjoint();
16028                            selections.select_anchor_ranges(ranges);
16029                        },
16030                    );
16031                }
16032            }
16033            editor.register_buffers_with_language_servers(cx);
16034        });
16035
16036        let item = Box::new(editor);
16037        let item_id = item.item_id();
16038
16039        if split {
16040            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16041        } else {
16042            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16043                let (preview_item_id, preview_item_idx) =
16044                    workspace.active_pane().read_with(cx, |pane, _| {
16045                        (pane.preview_item_id(), pane.preview_item_idx())
16046                    });
16047
16048                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16049
16050                if let Some(preview_item_id) = preview_item_id {
16051                    workspace.active_pane().update(cx, |pane, cx| {
16052                        pane.remove_item(preview_item_id, false, false, window, cx);
16053                    });
16054                }
16055            } else {
16056                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16057            }
16058        }
16059        workspace.active_pane().update(cx, |pane, cx| {
16060            pane.set_preview_item_id(Some(item_id), cx);
16061        });
16062    }
16063
16064    pub fn rename(
16065        &mut self,
16066        _: &Rename,
16067        window: &mut Window,
16068        cx: &mut Context<Self>,
16069    ) -> Option<Task<Result<()>>> {
16070        use language::ToOffset as _;
16071
16072        let provider = self.semantics_provider.clone()?;
16073        let selection = self.selections.newest_anchor().clone();
16074        let (cursor_buffer, cursor_buffer_position) = self
16075            .buffer
16076            .read(cx)
16077            .text_anchor_for_position(selection.head(), cx)?;
16078        let (tail_buffer, cursor_buffer_position_end) = self
16079            .buffer
16080            .read(cx)
16081            .text_anchor_for_position(selection.tail(), cx)?;
16082        if tail_buffer != cursor_buffer {
16083            return None;
16084        }
16085
16086        let snapshot = cursor_buffer.read(cx).snapshot();
16087        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16088        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16089        let prepare_rename = provider
16090            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16091            .unwrap_or_else(|| Task::ready(Ok(None)));
16092        drop(snapshot);
16093
16094        Some(cx.spawn_in(window, async move |this, cx| {
16095            let rename_range = if let Some(range) = prepare_rename.await? {
16096                Some(range)
16097            } else {
16098                this.update(cx, |this, cx| {
16099                    let buffer = this.buffer.read(cx).snapshot(cx);
16100                    let mut buffer_highlights = this
16101                        .document_highlights_for_position(selection.head(), &buffer)
16102                        .filter(|highlight| {
16103                            highlight.start.excerpt_id == selection.head().excerpt_id
16104                                && highlight.end.excerpt_id == selection.head().excerpt_id
16105                        });
16106                    buffer_highlights
16107                        .next()
16108                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16109                })?
16110            };
16111            if let Some(rename_range) = rename_range {
16112                this.update_in(cx, |this, window, cx| {
16113                    let snapshot = cursor_buffer.read(cx).snapshot();
16114                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16115                    let cursor_offset_in_rename_range =
16116                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16117                    let cursor_offset_in_rename_range_end =
16118                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16119
16120                    this.take_rename(false, window, cx);
16121                    let buffer = this.buffer.read(cx).read(cx);
16122                    let cursor_offset = selection.head().to_offset(&buffer);
16123                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16124                    let rename_end = rename_start + rename_buffer_range.len();
16125                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16126                    let mut old_highlight_id = None;
16127                    let old_name: Arc<str> = buffer
16128                        .chunks(rename_start..rename_end, true)
16129                        .map(|chunk| {
16130                            if old_highlight_id.is_none() {
16131                                old_highlight_id = chunk.syntax_highlight_id;
16132                            }
16133                            chunk.text
16134                        })
16135                        .collect::<String>()
16136                        .into();
16137
16138                    drop(buffer);
16139
16140                    // Position the selection in the rename editor so that it matches the current selection.
16141                    this.show_local_selections = false;
16142                    let rename_editor = cx.new(|cx| {
16143                        let mut editor = Editor::single_line(window, cx);
16144                        editor.buffer.update(cx, |buffer, cx| {
16145                            buffer.edit([(0..0, old_name.clone())], None, cx)
16146                        });
16147                        let rename_selection_range = match cursor_offset_in_rename_range
16148                            .cmp(&cursor_offset_in_rename_range_end)
16149                        {
16150                            Ordering::Equal => {
16151                                editor.select_all(&SelectAll, window, cx);
16152                                return editor;
16153                            }
16154                            Ordering::Less => {
16155                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16156                            }
16157                            Ordering::Greater => {
16158                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16159                            }
16160                        };
16161                        if rename_selection_range.end > old_name.len() {
16162                            editor.select_all(&SelectAll, window, cx);
16163                        } else {
16164                            editor.change_selections(Default::default(), window, cx, |s| {
16165                                s.select_ranges([rename_selection_range]);
16166                            });
16167                        }
16168                        editor
16169                    });
16170                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16171                        if e == &EditorEvent::Focused {
16172                            cx.emit(EditorEvent::FocusedIn)
16173                        }
16174                    })
16175                    .detach();
16176
16177                    let write_highlights =
16178                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16179                    let read_highlights =
16180                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16181                    let ranges = write_highlights
16182                        .iter()
16183                        .flat_map(|(_, ranges)| ranges.iter())
16184                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16185                        .cloned()
16186                        .collect();
16187
16188                    this.highlight_text::<Rename>(
16189                        ranges,
16190                        HighlightStyle {
16191                            fade_out: Some(0.6),
16192                            ..Default::default()
16193                        },
16194                        cx,
16195                    );
16196                    let rename_focus_handle = rename_editor.focus_handle(cx);
16197                    window.focus(&rename_focus_handle);
16198                    let block_id = this.insert_blocks(
16199                        [BlockProperties {
16200                            style: BlockStyle::Flex,
16201                            placement: BlockPlacement::Below(range.start),
16202                            height: Some(1),
16203                            render: Arc::new({
16204                                let rename_editor = rename_editor.clone();
16205                                move |cx: &mut BlockContext| {
16206                                    let mut text_style = cx.editor_style.text.clone();
16207                                    if let Some(highlight_style) = old_highlight_id
16208                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16209                                    {
16210                                        text_style = text_style.highlight(highlight_style);
16211                                    }
16212                                    div()
16213                                        .block_mouse_except_scroll()
16214                                        .pl(cx.anchor_x)
16215                                        .child(EditorElement::new(
16216                                            &rename_editor,
16217                                            EditorStyle {
16218                                                background: cx.theme().system().transparent,
16219                                                local_player: cx.editor_style.local_player,
16220                                                text: text_style,
16221                                                scrollbar_width: cx.editor_style.scrollbar_width,
16222                                                syntax: cx.editor_style.syntax.clone(),
16223                                                status: cx.editor_style.status.clone(),
16224                                                inlay_hints_style: HighlightStyle {
16225                                                    font_weight: Some(FontWeight::BOLD),
16226                                                    ..make_inlay_hints_style(cx.app)
16227                                                },
16228                                                inline_completion_styles: make_suggestion_styles(
16229                                                    cx.app,
16230                                                ),
16231                                                ..EditorStyle::default()
16232                                            },
16233                                        ))
16234                                        .into_any_element()
16235                                }
16236                            }),
16237                            priority: 0,
16238                        }],
16239                        Some(Autoscroll::fit()),
16240                        cx,
16241                    )[0];
16242                    this.pending_rename = Some(RenameState {
16243                        range,
16244                        old_name,
16245                        editor: rename_editor,
16246                        block_id,
16247                    });
16248                })?;
16249            }
16250
16251            Ok(())
16252        }))
16253    }
16254
16255    pub fn confirm_rename(
16256        &mut self,
16257        _: &ConfirmRename,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Option<Task<Result<()>>> {
16261        let rename = self.take_rename(false, window, cx)?;
16262        let workspace = self.workspace()?.downgrade();
16263        let (buffer, start) = self
16264            .buffer
16265            .read(cx)
16266            .text_anchor_for_position(rename.range.start, cx)?;
16267        let (end_buffer, _) = self
16268            .buffer
16269            .read(cx)
16270            .text_anchor_for_position(rename.range.end, cx)?;
16271        if buffer != end_buffer {
16272            return None;
16273        }
16274
16275        let old_name = rename.old_name;
16276        let new_name = rename.editor.read(cx).text(cx);
16277
16278        let rename = self.semantics_provider.as_ref()?.perform_rename(
16279            &buffer,
16280            start,
16281            new_name.clone(),
16282            cx,
16283        )?;
16284
16285        Some(cx.spawn_in(window, async move |editor, cx| {
16286            let project_transaction = rename.await?;
16287            Self::open_project_transaction(
16288                &editor,
16289                workspace,
16290                project_transaction,
16291                format!("Rename: {}{}", old_name, new_name),
16292                cx,
16293            )
16294            .await?;
16295
16296            editor.update(cx, |editor, cx| {
16297                editor.refresh_document_highlights(cx);
16298            })?;
16299            Ok(())
16300        }))
16301    }
16302
16303    fn take_rename(
16304        &mut self,
16305        moving_cursor: bool,
16306        window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) -> Option<RenameState> {
16309        let rename = self.pending_rename.take()?;
16310        if rename.editor.focus_handle(cx).is_focused(window) {
16311            window.focus(&self.focus_handle);
16312        }
16313
16314        self.remove_blocks(
16315            [rename.block_id].into_iter().collect(),
16316            Some(Autoscroll::fit()),
16317            cx,
16318        );
16319        self.clear_highlights::<Rename>(cx);
16320        self.show_local_selections = true;
16321
16322        if moving_cursor {
16323            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16324                editor.selections.newest::<usize>(cx).head()
16325            });
16326
16327            // Update the selection to match the position of the selection inside
16328            // the rename editor.
16329            let snapshot = self.buffer.read(cx).read(cx);
16330            let rename_range = rename.range.to_offset(&snapshot);
16331            let cursor_in_editor = snapshot
16332                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16333                .min(rename_range.end);
16334            drop(snapshot);
16335
16336            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16337                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16338            });
16339        } else {
16340            self.refresh_document_highlights(cx);
16341        }
16342
16343        Some(rename)
16344    }
16345
16346    pub fn pending_rename(&self) -> Option<&RenameState> {
16347        self.pending_rename.as_ref()
16348    }
16349
16350    fn format(
16351        &mut self,
16352        _: &Format,
16353        window: &mut Window,
16354        cx: &mut Context<Self>,
16355    ) -> Option<Task<Result<()>>> {
16356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16357
16358        let project = match &self.project {
16359            Some(project) => project.clone(),
16360            None => return None,
16361        };
16362
16363        Some(self.perform_format(
16364            project,
16365            FormatTrigger::Manual,
16366            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16367            window,
16368            cx,
16369        ))
16370    }
16371
16372    fn format_selections(
16373        &mut self,
16374        _: &FormatSelections,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) -> Option<Task<Result<()>>> {
16378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16379
16380        let project = match &self.project {
16381            Some(project) => project.clone(),
16382            None => return None,
16383        };
16384
16385        let ranges = self
16386            .selections
16387            .all_adjusted(cx)
16388            .into_iter()
16389            .map(|selection| selection.range())
16390            .collect_vec();
16391
16392        Some(self.perform_format(
16393            project,
16394            FormatTrigger::Manual,
16395            FormatTarget::Ranges(ranges),
16396            window,
16397            cx,
16398        ))
16399    }
16400
16401    fn perform_format(
16402        &mut self,
16403        project: Entity<Project>,
16404        trigger: FormatTrigger,
16405        target: FormatTarget,
16406        window: &mut Window,
16407        cx: &mut Context<Self>,
16408    ) -> Task<Result<()>> {
16409        let buffer = self.buffer.clone();
16410        let (buffers, target) = match target {
16411            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16412            FormatTarget::Ranges(selection_ranges) => {
16413                let multi_buffer = buffer.read(cx);
16414                let snapshot = multi_buffer.read(cx);
16415                let mut buffers = HashSet::default();
16416                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16417                    BTreeMap::new();
16418                for selection_range in selection_ranges {
16419                    for (buffer, buffer_range, _) in
16420                        snapshot.range_to_buffer_ranges(selection_range)
16421                    {
16422                        let buffer_id = buffer.remote_id();
16423                        let start = buffer.anchor_before(buffer_range.start);
16424                        let end = buffer.anchor_after(buffer_range.end);
16425                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16426                        buffer_id_to_ranges
16427                            .entry(buffer_id)
16428                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16429                            .or_insert_with(|| vec![start..end]);
16430                    }
16431                }
16432                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16433            }
16434        };
16435
16436        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16437        let selections_prev = transaction_id_prev
16438            .and_then(|transaction_id_prev| {
16439                // default to selections as they were after the last edit, if we have them,
16440                // instead of how they are now.
16441                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16442                // will take you back to where you made the last edit, instead of staying where you scrolled
16443                self.selection_history
16444                    .transaction(transaction_id_prev)
16445                    .map(|t| t.0.clone())
16446            })
16447            .unwrap_or_else(|| {
16448                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16449                self.selections.disjoint_anchors()
16450            });
16451
16452        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16453        let format = project.update(cx, |project, cx| {
16454            project.format(buffers, target, true, trigger, cx)
16455        });
16456
16457        cx.spawn_in(window, async move |editor, cx| {
16458            let transaction = futures::select_biased! {
16459                transaction = format.log_err().fuse() => transaction,
16460                () = timeout => {
16461                    log::warn!("timed out waiting for formatting");
16462                    None
16463                }
16464            };
16465
16466            buffer
16467                .update(cx, |buffer, cx| {
16468                    if let Some(transaction) = transaction {
16469                        if !buffer.is_singleton() {
16470                            buffer.push_transaction(&transaction.0, cx);
16471                        }
16472                    }
16473                    cx.notify();
16474                })
16475                .ok();
16476
16477            if let Some(transaction_id_now) =
16478                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16479            {
16480                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16481                if has_new_transaction {
16482                    _ = editor.update(cx, |editor, _| {
16483                        editor
16484                            .selection_history
16485                            .insert_transaction(transaction_id_now, selections_prev);
16486                    });
16487                }
16488            }
16489
16490            Ok(())
16491        })
16492    }
16493
16494    fn organize_imports(
16495        &mut self,
16496        _: &OrganizeImports,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) -> Option<Task<Result<()>>> {
16500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16501        let project = match &self.project {
16502            Some(project) => project.clone(),
16503            None => return None,
16504        };
16505        Some(self.perform_code_action_kind(
16506            project,
16507            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16508            window,
16509            cx,
16510        ))
16511    }
16512
16513    fn perform_code_action_kind(
16514        &mut self,
16515        project: Entity<Project>,
16516        kind: CodeActionKind,
16517        window: &mut Window,
16518        cx: &mut Context<Self>,
16519    ) -> Task<Result<()>> {
16520        let buffer = self.buffer.clone();
16521        let buffers = buffer.read(cx).all_buffers();
16522        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16523        let apply_action = project.update(cx, |project, cx| {
16524            project.apply_code_action_kind(buffers, kind, true, cx)
16525        });
16526        cx.spawn_in(window, async move |_, cx| {
16527            let transaction = futures::select_biased! {
16528                () = timeout => {
16529                    log::warn!("timed out waiting for executing code action");
16530                    None
16531                }
16532                transaction = apply_action.log_err().fuse() => transaction,
16533            };
16534            buffer
16535                .update(cx, |buffer, cx| {
16536                    // check if we need this
16537                    if let Some(transaction) = transaction {
16538                        if !buffer.is_singleton() {
16539                            buffer.push_transaction(&transaction.0, cx);
16540                        }
16541                    }
16542                    cx.notify();
16543                })
16544                .ok();
16545            Ok(())
16546        })
16547    }
16548
16549    pub fn restart_language_server(
16550        &mut self,
16551        _: &RestartLanguageServer,
16552        _: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) {
16555        if let Some(project) = self.project.clone() {
16556            self.buffer.update(cx, |multi_buffer, cx| {
16557                project.update(cx, |project, cx| {
16558                    project.restart_language_servers_for_buffers(
16559                        multi_buffer.all_buffers().into_iter().collect(),
16560                        HashSet::default(),
16561                        cx,
16562                    );
16563                });
16564            })
16565        }
16566    }
16567
16568    pub fn stop_language_server(
16569        &mut self,
16570        _: &StopLanguageServer,
16571        _: &mut Window,
16572        cx: &mut Context<Self>,
16573    ) {
16574        if let Some(project) = self.project.clone() {
16575            self.buffer.update(cx, |multi_buffer, cx| {
16576                project.update(cx, |project, cx| {
16577                    project.stop_language_servers_for_buffers(
16578                        multi_buffer.all_buffers().into_iter().collect(),
16579                        HashSet::default(),
16580                        cx,
16581                    );
16582                    cx.emit(project::Event::RefreshInlayHints);
16583                });
16584            });
16585        }
16586    }
16587
16588    fn cancel_language_server_work(
16589        workspace: &mut Workspace,
16590        _: &actions::CancelLanguageServerWork,
16591        _: &mut Window,
16592        cx: &mut Context<Workspace>,
16593    ) {
16594        let project = workspace.project();
16595        let buffers = workspace
16596            .active_item(cx)
16597            .and_then(|item| item.act_as::<Editor>(cx))
16598            .map_or(HashSet::default(), |editor| {
16599                editor.read(cx).buffer.read(cx).all_buffers()
16600            });
16601        project.update(cx, |project, cx| {
16602            project.cancel_language_server_work_for_buffers(buffers, cx);
16603        });
16604    }
16605
16606    fn show_character_palette(
16607        &mut self,
16608        _: &ShowCharacterPalette,
16609        window: &mut Window,
16610        _: &mut Context<Self>,
16611    ) {
16612        window.show_character_palette();
16613    }
16614
16615    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16616        if !self.diagnostics_enabled() {
16617            return;
16618        }
16619
16620        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16621            let buffer = self.buffer.read(cx).snapshot(cx);
16622            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16623            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16624            let is_valid = buffer
16625                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16626                .any(|entry| {
16627                    entry.diagnostic.is_primary
16628                        && !entry.range.is_empty()
16629                        && entry.range.start == primary_range_start
16630                        && entry.diagnostic.message == active_diagnostics.active_message
16631                });
16632
16633            if !is_valid {
16634                self.dismiss_diagnostics(cx);
16635            }
16636        }
16637    }
16638
16639    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16640        match &self.active_diagnostics {
16641            ActiveDiagnostic::Group(group) => Some(group),
16642            _ => None,
16643        }
16644    }
16645
16646    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16647        if !self.diagnostics_enabled() {
16648            return;
16649        }
16650        self.dismiss_diagnostics(cx);
16651        self.active_diagnostics = ActiveDiagnostic::All;
16652    }
16653
16654    fn activate_diagnostics(
16655        &mut self,
16656        buffer_id: BufferId,
16657        diagnostic: DiagnosticEntry<usize>,
16658        window: &mut Window,
16659        cx: &mut Context<Self>,
16660    ) {
16661        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16662            return;
16663        }
16664        self.dismiss_diagnostics(cx);
16665        let snapshot = self.snapshot(window, cx);
16666        let buffer = self.buffer.read(cx).snapshot(cx);
16667        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16668            return;
16669        };
16670
16671        let diagnostic_group = buffer
16672            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16673            .collect::<Vec<_>>();
16674
16675        let blocks =
16676            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16677
16678        let blocks = self.display_map.update(cx, |display_map, cx| {
16679            display_map.insert_blocks(blocks, cx).into_iter().collect()
16680        });
16681        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16682            active_range: buffer.anchor_before(diagnostic.range.start)
16683                ..buffer.anchor_after(diagnostic.range.end),
16684            active_message: diagnostic.diagnostic.message.clone(),
16685            group_id: diagnostic.diagnostic.group_id,
16686            blocks,
16687        });
16688        cx.notify();
16689    }
16690
16691    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16692        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16693            return;
16694        };
16695
16696        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16697        if let ActiveDiagnostic::Group(group) = prev {
16698            self.display_map.update(cx, |display_map, cx| {
16699                display_map.remove_blocks(group.blocks, cx);
16700            });
16701            cx.notify();
16702        }
16703    }
16704
16705    /// Disable inline diagnostics rendering for this editor.
16706    pub fn disable_inline_diagnostics(&mut self) {
16707        self.inline_diagnostics_enabled = false;
16708        self.inline_diagnostics_update = Task::ready(());
16709        self.inline_diagnostics.clear();
16710    }
16711
16712    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16713        self.diagnostics_enabled = false;
16714        self.dismiss_diagnostics(cx);
16715        self.inline_diagnostics_update = Task::ready(());
16716        self.inline_diagnostics.clear();
16717    }
16718
16719    pub fn diagnostics_enabled(&self) -> bool {
16720        self.diagnostics_enabled && self.mode.is_full()
16721    }
16722
16723    pub fn inline_diagnostics_enabled(&self) -> bool {
16724        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16725    }
16726
16727    pub fn show_inline_diagnostics(&self) -> bool {
16728        self.show_inline_diagnostics
16729    }
16730
16731    pub fn toggle_inline_diagnostics(
16732        &mut self,
16733        _: &ToggleInlineDiagnostics,
16734        window: &mut Window,
16735        cx: &mut Context<Editor>,
16736    ) {
16737        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16738        self.refresh_inline_diagnostics(false, window, cx);
16739    }
16740
16741    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16742        self.diagnostics_max_severity = severity;
16743        self.display_map.update(cx, |display_map, _| {
16744            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16745        });
16746    }
16747
16748    pub fn toggle_diagnostics(
16749        &mut self,
16750        _: &ToggleDiagnostics,
16751        window: &mut Window,
16752        cx: &mut Context<Editor>,
16753    ) {
16754        if !self.diagnostics_enabled() {
16755            return;
16756        }
16757
16758        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16759            EditorSettings::get_global(cx)
16760                .diagnostics_max_severity
16761                .filter(|severity| severity != &DiagnosticSeverity::Off)
16762                .unwrap_or(DiagnosticSeverity::Hint)
16763        } else {
16764            DiagnosticSeverity::Off
16765        };
16766        self.set_max_diagnostics_severity(new_severity, cx);
16767        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16768            self.active_diagnostics = ActiveDiagnostic::None;
16769            self.inline_diagnostics_update = Task::ready(());
16770            self.inline_diagnostics.clear();
16771        } else {
16772            self.refresh_inline_diagnostics(false, window, cx);
16773        }
16774
16775        cx.notify();
16776    }
16777
16778    pub fn toggle_minimap(
16779        &mut self,
16780        _: &ToggleMinimap,
16781        window: &mut Window,
16782        cx: &mut Context<Editor>,
16783    ) {
16784        if self.supports_minimap(cx) {
16785            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16786        }
16787    }
16788
16789    fn refresh_inline_diagnostics(
16790        &mut self,
16791        debounce: bool,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        let max_severity = ProjectSettings::get_global(cx)
16796            .diagnostics
16797            .inline
16798            .max_severity
16799            .unwrap_or(self.diagnostics_max_severity);
16800
16801        if !self.inline_diagnostics_enabled()
16802            || !self.show_inline_diagnostics
16803            || max_severity == DiagnosticSeverity::Off
16804        {
16805            self.inline_diagnostics_update = Task::ready(());
16806            self.inline_diagnostics.clear();
16807            return;
16808        }
16809
16810        let debounce_ms = ProjectSettings::get_global(cx)
16811            .diagnostics
16812            .inline
16813            .update_debounce_ms;
16814        let debounce = if debounce && debounce_ms > 0 {
16815            Some(Duration::from_millis(debounce_ms))
16816        } else {
16817            None
16818        };
16819        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16820            if let Some(debounce) = debounce {
16821                cx.background_executor().timer(debounce).await;
16822            }
16823            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16824                editor
16825                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16826                    .ok()
16827            }) else {
16828                return;
16829            };
16830
16831            let new_inline_diagnostics = cx
16832                .background_spawn(async move {
16833                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16834                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16835                        let message = diagnostic_entry
16836                            .diagnostic
16837                            .message
16838                            .split_once('\n')
16839                            .map(|(line, _)| line)
16840                            .map(SharedString::new)
16841                            .unwrap_or_else(|| {
16842                                SharedString::from(diagnostic_entry.diagnostic.message)
16843                            });
16844                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16845                        let (Ok(i) | Err(i)) = inline_diagnostics
16846                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16847                        inline_diagnostics.insert(
16848                            i,
16849                            (
16850                                start_anchor,
16851                                InlineDiagnostic {
16852                                    message,
16853                                    group_id: diagnostic_entry.diagnostic.group_id,
16854                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16855                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16856                                    severity: diagnostic_entry.diagnostic.severity,
16857                                },
16858                            ),
16859                        );
16860                    }
16861                    inline_diagnostics
16862                })
16863                .await;
16864
16865            editor
16866                .update(cx, |editor, cx| {
16867                    editor.inline_diagnostics = new_inline_diagnostics;
16868                    cx.notify();
16869                })
16870                .ok();
16871        });
16872    }
16873
16874    fn pull_diagnostics(
16875        &mut self,
16876        buffer_id: Option<BufferId>,
16877        window: &Window,
16878        cx: &mut Context<Self>,
16879    ) -> Option<()> {
16880        if !self.mode().is_full() {
16881            return None;
16882        }
16883        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16884            .diagnostics
16885            .lsp_pull_diagnostics;
16886        if !pull_diagnostics_settings.enabled {
16887            return None;
16888        }
16889        let project = self.project.as_ref()?.downgrade();
16890        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16891        let mut buffers = self.buffer.read(cx).all_buffers();
16892        if let Some(buffer_id) = buffer_id {
16893            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16894        }
16895
16896        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16897            cx.background_executor().timer(debounce).await;
16898
16899            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16900                buffers
16901                    .into_iter()
16902                    .filter_map(|buffer| {
16903                        project
16904                            .update(cx, |project, cx| {
16905                                project.lsp_store().update(cx, |lsp_store, cx| {
16906                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16907                                })
16908                            })
16909                            .ok()
16910                    })
16911                    .collect::<FuturesUnordered<_>>()
16912            }) else {
16913                return;
16914            };
16915
16916            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16917                match pull_task {
16918                    Ok(()) => {
16919                        if editor
16920                            .update_in(cx, |editor, window, cx| {
16921                                editor.update_diagnostics_state(window, cx);
16922                            })
16923                            .is_err()
16924                        {
16925                            return;
16926                        }
16927                    }
16928                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16929                }
16930            }
16931        });
16932
16933        Some(())
16934    }
16935
16936    pub fn set_selections_from_remote(
16937        &mut self,
16938        selections: Vec<Selection<Anchor>>,
16939        pending_selection: Option<Selection<Anchor>>,
16940        window: &mut Window,
16941        cx: &mut Context<Self>,
16942    ) {
16943        let old_cursor_position = self.selections.newest_anchor().head();
16944        self.selections.change_with(cx, |s| {
16945            s.select_anchors(selections);
16946            if let Some(pending_selection) = pending_selection {
16947                s.set_pending(pending_selection, SelectMode::Character);
16948            } else {
16949                s.clear_pending();
16950            }
16951        });
16952        self.selections_did_change(
16953            false,
16954            &old_cursor_position,
16955            SelectionEffects::default(),
16956            window,
16957            cx,
16958        );
16959    }
16960
16961    pub fn transact(
16962        &mut self,
16963        window: &mut Window,
16964        cx: &mut Context<Self>,
16965        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16966    ) -> Option<TransactionId> {
16967        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16968            this.start_transaction_at(Instant::now(), window, cx);
16969            update(this, window, cx);
16970            this.end_transaction_at(Instant::now(), cx)
16971        })
16972    }
16973
16974    pub fn start_transaction_at(
16975        &mut self,
16976        now: Instant,
16977        window: &mut Window,
16978        cx: &mut Context<Self>,
16979    ) -> Option<TransactionId> {
16980        self.end_selection(window, cx);
16981        if let Some(tx_id) = self
16982            .buffer
16983            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16984        {
16985            self.selection_history
16986                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16987            cx.emit(EditorEvent::TransactionBegun {
16988                transaction_id: tx_id,
16989            });
16990            Some(tx_id)
16991        } else {
16992            None
16993        }
16994    }
16995
16996    pub fn end_transaction_at(
16997        &mut self,
16998        now: Instant,
16999        cx: &mut Context<Self>,
17000    ) -> Option<TransactionId> {
17001        if let Some(transaction_id) = self
17002            .buffer
17003            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17004        {
17005            if let Some((_, end_selections)) =
17006                self.selection_history.transaction_mut(transaction_id)
17007            {
17008                *end_selections = Some(self.selections.disjoint_anchors());
17009            } else {
17010                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17011            }
17012
17013            cx.emit(EditorEvent::Edited { transaction_id });
17014            Some(transaction_id)
17015        } else {
17016            None
17017        }
17018    }
17019
17020    pub fn modify_transaction_selection_history(
17021        &mut self,
17022        transaction_id: TransactionId,
17023        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17024    ) -> bool {
17025        self.selection_history
17026            .transaction_mut(transaction_id)
17027            .map(modify)
17028            .is_some()
17029    }
17030
17031    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17032        if self.selection_mark_mode {
17033            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17034                s.move_with(|_, sel| {
17035                    sel.collapse_to(sel.head(), SelectionGoal::None);
17036                });
17037            })
17038        }
17039        self.selection_mark_mode = true;
17040        cx.notify();
17041    }
17042
17043    pub fn swap_selection_ends(
17044        &mut self,
17045        _: &actions::SwapSelectionEnds,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17050            s.move_with(|_, sel| {
17051                if sel.start != sel.end {
17052                    sel.reversed = !sel.reversed
17053                }
17054            });
17055        });
17056        self.request_autoscroll(Autoscroll::newest(), cx);
17057        cx.notify();
17058    }
17059
17060    pub fn toggle_focus(
17061        workspace: &mut Workspace,
17062        _: &actions::ToggleFocus,
17063        window: &mut Window,
17064        cx: &mut Context<Workspace>,
17065    ) {
17066        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17067            return;
17068        };
17069        workspace.activate_item(&item, true, true, window, cx);
17070    }
17071
17072    pub fn toggle_fold(
17073        &mut self,
17074        _: &actions::ToggleFold,
17075        window: &mut Window,
17076        cx: &mut Context<Self>,
17077    ) {
17078        if self.is_singleton(cx) {
17079            let selection = self.selections.newest::<Point>(cx);
17080
17081            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17082            let range = if selection.is_empty() {
17083                let point = selection.head().to_display_point(&display_map);
17084                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17085                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17086                    .to_point(&display_map);
17087                start..end
17088            } else {
17089                selection.range()
17090            };
17091            if display_map.folds_in_range(range).next().is_some() {
17092                self.unfold_lines(&Default::default(), window, cx)
17093            } else {
17094                self.fold(&Default::default(), window, cx)
17095            }
17096        } else {
17097            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17098            let buffer_ids: HashSet<_> = self
17099                .selections
17100                .disjoint_anchor_ranges()
17101                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17102                .collect();
17103
17104            let should_unfold = buffer_ids
17105                .iter()
17106                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17107
17108            for buffer_id in buffer_ids {
17109                if should_unfold {
17110                    self.unfold_buffer(buffer_id, cx);
17111                } else {
17112                    self.fold_buffer(buffer_id, cx);
17113                }
17114            }
17115        }
17116    }
17117
17118    pub fn toggle_fold_recursive(
17119        &mut self,
17120        _: &actions::ToggleFoldRecursive,
17121        window: &mut Window,
17122        cx: &mut Context<Self>,
17123    ) {
17124        let selection = self.selections.newest::<Point>(cx);
17125
17126        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17127        let range = if selection.is_empty() {
17128            let point = selection.head().to_display_point(&display_map);
17129            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17130            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17131                .to_point(&display_map);
17132            start..end
17133        } else {
17134            selection.range()
17135        };
17136        if display_map.folds_in_range(range).next().is_some() {
17137            self.unfold_recursive(&Default::default(), window, cx)
17138        } else {
17139            self.fold_recursive(&Default::default(), window, cx)
17140        }
17141    }
17142
17143    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17144        if self.is_singleton(cx) {
17145            let mut to_fold = Vec::new();
17146            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17147            let selections = self.selections.all_adjusted(cx);
17148
17149            for selection in selections {
17150                let range = selection.range().sorted();
17151                let buffer_start_row = range.start.row;
17152
17153                if range.start.row != range.end.row {
17154                    let mut found = false;
17155                    let mut row = range.start.row;
17156                    while row <= range.end.row {
17157                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17158                        {
17159                            found = true;
17160                            row = crease.range().end.row + 1;
17161                            to_fold.push(crease);
17162                        } else {
17163                            row += 1
17164                        }
17165                    }
17166                    if found {
17167                        continue;
17168                    }
17169                }
17170
17171                for row in (0..=range.start.row).rev() {
17172                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17173                        if crease.range().end.row >= buffer_start_row {
17174                            to_fold.push(crease);
17175                            if row <= range.start.row {
17176                                break;
17177                            }
17178                        }
17179                    }
17180                }
17181            }
17182
17183            self.fold_creases(to_fold, true, window, cx);
17184        } else {
17185            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17186            let buffer_ids = self
17187                .selections
17188                .disjoint_anchor_ranges()
17189                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17190                .collect::<HashSet<_>>();
17191            for buffer_id in buffer_ids {
17192                self.fold_buffer(buffer_id, cx);
17193            }
17194        }
17195    }
17196
17197    pub fn toggle_fold_all(
17198        &mut self,
17199        _: &actions::ToggleFoldAll,
17200        window: &mut Window,
17201        cx: &mut Context<Self>,
17202    ) {
17203        if self.buffer.read(cx).is_singleton() {
17204            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17205            let has_folds = display_map
17206                .folds_in_range(0..display_map.buffer_snapshot.len())
17207                .next()
17208                .is_some();
17209
17210            if has_folds {
17211                self.unfold_all(&actions::UnfoldAll, window, cx);
17212            } else {
17213                self.fold_all(&actions::FoldAll, window, cx);
17214            }
17215        } else {
17216            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17217            let should_unfold = buffer_ids
17218                .iter()
17219                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17220
17221            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17222                editor
17223                    .update_in(cx, |editor, _, cx| {
17224                        for buffer_id in buffer_ids {
17225                            if should_unfold {
17226                                editor.unfold_buffer(buffer_id, cx);
17227                            } else {
17228                                editor.fold_buffer(buffer_id, cx);
17229                            }
17230                        }
17231                    })
17232                    .ok();
17233            });
17234        }
17235    }
17236
17237    fn fold_at_level(
17238        &mut self,
17239        fold_at: &FoldAtLevel,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) {
17243        if !self.buffer.read(cx).is_singleton() {
17244            return;
17245        }
17246
17247        let fold_at_level = fold_at.0;
17248        let snapshot = self.buffer.read(cx).snapshot(cx);
17249        let mut to_fold = Vec::new();
17250        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17251
17252        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17253            while start_row < end_row {
17254                match self
17255                    .snapshot(window, cx)
17256                    .crease_for_buffer_row(MultiBufferRow(start_row))
17257                {
17258                    Some(crease) => {
17259                        let nested_start_row = crease.range().start.row + 1;
17260                        let nested_end_row = crease.range().end.row;
17261
17262                        if current_level < fold_at_level {
17263                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17264                        } else if current_level == fold_at_level {
17265                            to_fold.push(crease);
17266                        }
17267
17268                        start_row = nested_end_row + 1;
17269                    }
17270                    None => start_row += 1,
17271                }
17272            }
17273        }
17274
17275        self.fold_creases(to_fold, true, window, cx);
17276    }
17277
17278    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17279        if self.buffer.read(cx).is_singleton() {
17280            let mut fold_ranges = Vec::new();
17281            let snapshot = self.buffer.read(cx).snapshot(cx);
17282
17283            for row in 0..snapshot.max_row().0 {
17284                if let Some(foldable_range) = self
17285                    .snapshot(window, cx)
17286                    .crease_for_buffer_row(MultiBufferRow(row))
17287                {
17288                    fold_ranges.push(foldable_range);
17289                }
17290            }
17291
17292            self.fold_creases(fold_ranges, true, window, cx);
17293        } else {
17294            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17295                editor
17296                    .update_in(cx, |editor, _, cx| {
17297                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17298                            editor.fold_buffer(buffer_id, cx);
17299                        }
17300                    })
17301                    .ok();
17302            });
17303        }
17304    }
17305
17306    pub fn fold_function_bodies(
17307        &mut self,
17308        _: &actions::FoldFunctionBodies,
17309        window: &mut Window,
17310        cx: &mut Context<Self>,
17311    ) {
17312        let snapshot = self.buffer.read(cx).snapshot(cx);
17313
17314        let ranges = snapshot
17315            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17316            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17317            .collect::<Vec<_>>();
17318
17319        let creases = ranges
17320            .into_iter()
17321            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17322            .collect();
17323
17324        self.fold_creases(creases, true, window, cx);
17325    }
17326
17327    pub fn fold_recursive(
17328        &mut self,
17329        _: &actions::FoldRecursive,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) {
17333        let mut to_fold = Vec::new();
17334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17335        let selections = self.selections.all_adjusted(cx);
17336
17337        for selection in selections {
17338            let range = selection.range().sorted();
17339            let buffer_start_row = range.start.row;
17340
17341            if range.start.row != range.end.row {
17342                let mut found = false;
17343                for row in range.start.row..=range.end.row {
17344                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17345                        found = true;
17346                        to_fold.push(crease);
17347                    }
17348                }
17349                if found {
17350                    continue;
17351                }
17352            }
17353
17354            for row in (0..=range.start.row).rev() {
17355                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17356                    if crease.range().end.row >= buffer_start_row {
17357                        to_fold.push(crease);
17358                    } else {
17359                        break;
17360                    }
17361                }
17362            }
17363        }
17364
17365        self.fold_creases(to_fold, true, window, cx);
17366    }
17367
17368    pub fn fold_at(
17369        &mut self,
17370        buffer_row: MultiBufferRow,
17371        window: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) {
17374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17375
17376        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17377            let autoscroll = self
17378                .selections
17379                .all::<Point>(cx)
17380                .iter()
17381                .any(|selection| crease.range().overlaps(&selection.range()));
17382
17383            self.fold_creases(vec![crease], autoscroll, window, cx);
17384        }
17385    }
17386
17387    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17388        if self.is_singleton(cx) {
17389            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17390            let buffer = &display_map.buffer_snapshot;
17391            let selections = self.selections.all::<Point>(cx);
17392            let ranges = selections
17393                .iter()
17394                .map(|s| {
17395                    let range = s.display_range(&display_map).sorted();
17396                    let mut start = range.start.to_point(&display_map);
17397                    let mut end = range.end.to_point(&display_map);
17398                    start.column = 0;
17399                    end.column = buffer.line_len(MultiBufferRow(end.row));
17400                    start..end
17401                })
17402                .collect::<Vec<_>>();
17403
17404            self.unfold_ranges(&ranges, true, true, cx);
17405        } else {
17406            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17407            let buffer_ids = self
17408                .selections
17409                .disjoint_anchor_ranges()
17410                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17411                .collect::<HashSet<_>>();
17412            for buffer_id in buffer_ids {
17413                self.unfold_buffer(buffer_id, cx);
17414            }
17415        }
17416    }
17417
17418    pub fn unfold_recursive(
17419        &mut self,
17420        _: &UnfoldRecursive,
17421        _window: &mut Window,
17422        cx: &mut Context<Self>,
17423    ) {
17424        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17425        let selections = self.selections.all::<Point>(cx);
17426        let ranges = selections
17427            .iter()
17428            .map(|s| {
17429                let mut range = s.display_range(&display_map).sorted();
17430                *range.start.column_mut() = 0;
17431                *range.end.column_mut() = display_map.line_len(range.end.row());
17432                let start = range.start.to_point(&display_map);
17433                let end = range.end.to_point(&display_map);
17434                start..end
17435            })
17436            .collect::<Vec<_>>();
17437
17438        self.unfold_ranges(&ranges, true, true, cx);
17439    }
17440
17441    pub fn unfold_at(
17442        &mut self,
17443        buffer_row: MultiBufferRow,
17444        _window: &mut Window,
17445        cx: &mut Context<Self>,
17446    ) {
17447        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17448
17449        let intersection_range = Point::new(buffer_row.0, 0)
17450            ..Point::new(
17451                buffer_row.0,
17452                display_map.buffer_snapshot.line_len(buffer_row),
17453            );
17454
17455        let autoscroll = self
17456            .selections
17457            .all::<Point>(cx)
17458            .iter()
17459            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17460
17461        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17462    }
17463
17464    pub fn unfold_all(
17465        &mut self,
17466        _: &actions::UnfoldAll,
17467        _window: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        if self.buffer.read(cx).is_singleton() {
17471            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17472            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17473        } else {
17474            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17475                editor
17476                    .update(cx, |editor, cx| {
17477                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17478                            editor.unfold_buffer(buffer_id, cx);
17479                        }
17480                    })
17481                    .ok();
17482            });
17483        }
17484    }
17485
17486    pub fn fold_selected_ranges(
17487        &mut self,
17488        _: &FoldSelectedRanges,
17489        window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        let selections = self.selections.all_adjusted(cx);
17493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17494        let ranges = selections
17495            .into_iter()
17496            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17497            .collect::<Vec<_>>();
17498        self.fold_creases(ranges, true, window, cx);
17499    }
17500
17501    pub fn fold_ranges<T: ToOffset + Clone>(
17502        &mut self,
17503        ranges: Vec<Range<T>>,
17504        auto_scroll: bool,
17505        window: &mut Window,
17506        cx: &mut Context<Self>,
17507    ) {
17508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17509        let ranges = ranges
17510            .into_iter()
17511            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17512            .collect::<Vec<_>>();
17513        self.fold_creases(ranges, auto_scroll, window, cx);
17514    }
17515
17516    pub fn fold_creases<T: ToOffset + Clone>(
17517        &mut self,
17518        creases: Vec<Crease<T>>,
17519        auto_scroll: bool,
17520        _window: &mut Window,
17521        cx: &mut Context<Self>,
17522    ) {
17523        if creases.is_empty() {
17524            return;
17525        }
17526
17527        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17528
17529        if auto_scroll {
17530            self.request_autoscroll(Autoscroll::fit(), cx);
17531        }
17532
17533        cx.notify();
17534
17535        self.scrollbar_marker_state.dirty = true;
17536        self.folds_did_change(cx);
17537    }
17538
17539    /// Removes any folds whose ranges intersect any of the given ranges.
17540    pub fn unfold_ranges<T: ToOffset + Clone>(
17541        &mut self,
17542        ranges: &[Range<T>],
17543        inclusive: bool,
17544        auto_scroll: bool,
17545        cx: &mut Context<Self>,
17546    ) {
17547        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17548            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17549        });
17550        self.folds_did_change(cx);
17551    }
17552
17553    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17554        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17555            return;
17556        }
17557        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17558        self.display_map.update(cx, |display_map, cx| {
17559            display_map.fold_buffers([buffer_id], cx)
17560        });
17561        cx.emit(EditorEvent::BufferFoldToggled {
17562            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17563            folded: true,
17564        });
17565        cx.notify();
17566    }
17567
17568    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17569        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17570            return;
17571        }
17572        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17573        self.display_map.update(cx, |display_map, cx| {
17574            display_map.unfold_buffers([buffer_id], cx);
17575        });
17576        cx.emit(EditorEvent::BufferFoldToggled {
17577            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17578            folded: false,
17579        });
17580        cx.notify();
17581    }
17582
17583    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17584        self.display_map.read(cx).is_buffer_folded(buffer)
17585    }
17586
17587    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17588        self.display_map.read(cx).folded_buffers()
17589    }
17590
17591    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17592        self.display_map.update(cx, |display_map, cx| {
17593            display_map.disable_header_for_buffer(buffer_id, cx);
17594        });
17595        cx.notify();
17596    }
17597
17598    /// Removes any folds with the given ranges.
17599    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17600        &mut self,
17601        ranges: &[Range<T>],
17602        type_id: TypeId,
17603        auto_scroll: bool,
17604        cx: &mut Context<Self>,
17605    ) {
17606        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17607            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17608        });
17609        self.folds_did_change(cx);
17610    }
17611
17612    fn remove_folds_with<T: ToOffset + Clone>(
17613        &mut self,
17614        ranges: &[Range<T>],
17615        auto_scroll: bool,
17616        cx: &mut Context<Self>,
17617        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17618    ) {
17619        if ranges.is_empty() {
17620            return;
17621        }
17622
17623        let mut buffers_affected = HashSet::default();
17624        let multi_buffer = self.buffer().read(cx);
17625        for range in ranges {
17626            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17627                buffers_affected.insert(buffer.read(cx).remote_id());
17628            };
17629        }
17630
17631        self.display_map.update(cx, update);
17632
17633        if auto_scroll {
17634            self.request_autoscroll(Autoscroll::fit(), cx);
17635        }
17636
17637        cx.notify();
17638        self.scrollbar_marker_state.dirty = true;
17639        self.active_indent_guides_state.dirty = true;
17640    }
17641
17642    pub fn update_renderer_widths(
17643        &mut self,
17644        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17645        cx: &mut Context<Self>,
17646    ) -> bool {
17647        self.display_map
17648            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17649    }
17650
17651    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17652        self.display_map.read(cx).fold_placeholder.clone()
17653    }
17654
17655    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17656        self.buffer.update(cx, |buffer, cx| {
17657            buffer.set_all_diff_hunks_expanded(cx);
17658        });
17659    }
17660
17661    pub fn expand_all_diff_hunks(
17662        &mut self,
17663        _: &ExpandAllDiffHunks,
17664        _window: &mut Window,
17665        cx: &mut Context<Self>,
17666    ) {
17667        self.buffer.update(cx, |buffer, cx| {
17668            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17669        });
17670    }
17671
17672    pub fn toggle_selected_diff_hunks(
17673        &mut self,
17674        _: &ToggleSelectedDiffHunks,
17675        _window: &mut Window,
17676        cx: &mut Context<Self>,
17677    ) {
17678        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17679        self.toggle_diff_hunks_in_ranges(ranges, cx);
17680    }
17681
17682    pub fn diff_hunks_in_ranges<'a>(
17683        &'a self,
17684        ranges: &'a [Range<Anchor>],
17685        buffer: &'a MultiBufferSnapshot,
17686    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17687        ranges.iter().flat_map(move |range| {
17688            let end_excerpt_id = range.end.excerpt_id;
17689            let range = range.to_point(buffer);
17690            let mut peek_end = range.end;
17691            if range.end.row < buffer.max_row().0 {
17692                peek_end = Point::new(range.end.row + 1, 0);
17693            }
17694            buffer
17695                .diff_hunks_in_range(range.start..peek_end)
17696                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17697        })
17698    }
17699
17700    pub fn has_stageable_diff_hunks_in_ranges(
17701        &self,
17702        ranges: &[Range<Anchor>],
17703        snapshot: &MultiBufferSnapshot,
17704    ) -> bool {
17705        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17706        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17707    }
17708
17709    pub fn toggle_staged_selected_diff_hunks(
17710        &mut self,
17711        _: &::git::ToggleStaged,
17712        _: &mut Window,
17713        cx: &mut Context<Self>,
17714    ) {
17715        let snapshot = self.buffer.read(cx).snapshot(cx);
17716        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17717        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17718        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17719    }
17720
17721    pub fn set_render_diff_hunk_controls(
17722        &mut self,
17723        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17724        cx: &mut Context<Self>,
17725    ) {
17726        self.render_diff_hunk_controls = render_diff_hunk_controls;
17727        cx.notify();
17728    }
17729
17730    pub fn stage_and_next(
17731        &mut self,
17732        _: &::git::StageAndNext,
17733        window: &mut Window,
17734        cx: &mut Context<Self>,
17735    ) {
17736        self.do_stage_or_unstage_and_next(true, window, cx);
17737    }
17738
17739    pub fn unstage_and_next(
17740        &mut self,
17741        _: &::git::UnstageAndNext,
17742        window: &mut Window,
17743        cx: &mut Context<Self>,
17744    ) {
17745        self.do_stage_or_unstage_and_next(false, window, cx);
17746    }
17747
17748    pub fn stage_or_unstage_diff_hunks(
17749        &mut self,
17750        stage: bool,
17751        ranges: Vec<Range<Anchor>>,
17752        cx: &mut Context<Self>,
17753    ) {
17754        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17755        cx.spawn(async move |this, cx| {
17756            task.await?;
17757            this.update(cx, |this, cx| {
17758                let snapshot = this.buffer.read(cx).snapshot(cx);
17759                let chunk_by = this
17760                    .diff_hunks_in_ranges(&ranges, &snapshot)
17761                    .chunk_by(|hunk| hunk.buffer_id);
17762                for (buffer_id, hunks) in &chunk_by {
17763                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17764                }
17765            })
17766        })
17767        .detach_and_log_err(cx);
17768    }
17769
17770    fn save_buffers_for_ranges_if_needed(
17771        &mut self,
17772        ranges: &[Range<Anchor>],
17773        cx: &mut Context<Editor>,
17774    ) -> Task<Result<()>> {
17775        let multibuffer = self.buffer.read(cx);
17776        let snapshot = multibuffer.read(cx);
17777        let buffer_ids: HashSet<_> = ranges
17778            .iter()
17779            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17780            .collect();
17781        drop(snapshot);
17782
17783        let mut buffers = HashSet::default();
17784        for buffer_id in buffer_ids {
17785            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17786                let buffer = buffer_entity.read(cx);
17787                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17788                {
17789                    buffers.insert(buffer_entity);
17790                }
17791            }
17792        }
17793
17794        if let Some(project) = &self.project {
17795            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17796        } else {
17797            Task::ready(Ok(()))
17798        }
17799    }
17800
17801    fn do_stage_or_unstage_and_next(
17802        &mut self,
17803        stage: bool,
17804        window: &mut Window,
17805        cx: &mut Context<Self>,
17806    ) {
17807        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17808
17809        if ranges.iter().any(|range| range.start != range.end) {
17810            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17811            return;
17812        }
17813
17814        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17815        let snapshot = self.snapshot(window, cx);
17816        let position = self.selections.newest::<Point>(cx).head();
17817        let mut row = snapshot
17818            .buffer_snapshot
17819            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17820            .find(|hunk| hunk.row_range.start.0 > position.row)
17821            .map(|hunk| hunk.row_range.start);
17822
17823        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17824        // Outside of the project diff editor, wrap around to the beginning.
17825        if !all_diff_hunks_expanded {
17826            row = row.or_else(|| {
17827                snapshot
17828                    .buffer_snapshot
17829                    .diff_hunks_in_range(Point::zero()..position)
17830                    .find(|hunk| hunk.row_range.end.0 < position.row)
17831                    .map(|hunk| hunk.row_range.start)
17832            });
17833        }
17834
17835        if let Some(row) = row {
17836            let destination = Point::new(row.0, 0);
17837            let autoscroll = Autoscroll::center();
17838
17839            self.unfold_ranges(&[destination..destination], false, false, cx);
17840            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17841                s.select_ranges([destination..destination]);
17842            });
17843        }
17844    }
17845
17846    fn do_stage_or_unstage(
17847        &self,
17848        stage: bool,
17849        buffer_id: BufferId,
17850        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17851        cx: &mut App,
17852    ) -> Option<()> {
17853        let project = self.project.as_ref()?;
17854        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17855        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17856        let buffer_snapshot = buffer.read(cx).snapshot();
17857        let file_exists = buffer_snapshot
17858            .file()
17859            .is_some_and(|file| file.disk_state().exists());
17860        diff.update(cx, |diff, cx| {
17861            diff.stage_or_unstage_hunks(
17862                stage,
17863                &hunks
17864                    .map(|hunk| buffer_diff::DiffHunk {
17865                        buffer_range: hunk.buffer_range,
17866                        diff_base_byte_range: hunk.diff_base_byte_range,
17867                        secondary_status: hunk.secondary_status,
17868                        range: Point::zero()..Point::zero(), // unused
17869                    })
17870                    .collect::<Vec<_>>(),
17871                &buffer_snapshot,
17872                file_exists,
17873                cx,
17874            )
17875        });
17876        None
17877    }
17878
17879    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17880        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17881        self.buffer
17882            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17883    }
17884
17885    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17886        self.buffer.update(cx, |buffer, cx| {
17887            let ranges = vec![Anchor::min()..Anchor::max()];
17888            if !buffer.all_diff_hunks_expanded()
17889                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17890            {
17891                buffer.collapse_diff_hunks(ranges, cx);
17892                true
17893            } else {
17894                false
17895            }
17896        })
17897    }
17898
17899    fn toggle_diff_hunks_in_ranges(
17900        &mut self,
17901        ranges: Vec<Range<Anchor>>,
17902        cx: &mut Context<Editor>,
17903    ) {
17904        self.buffer.update(cx, |buffer, cx| {
17905            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17906            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17907        })
17908    }
17909
17910    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17911        self.buffer.update(cx, |buffer, cx| {
17912            let snapshot = buffer.snapshot(cx);
17913            let excerpt_id = range.end.excerpt_id;
17914            let point_range = range.to_point(&snapshot);
17915            let expand = !buffer.single_hunk_is_expanded(range, cx);
17916            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17917        })
17918    }
17919
17920    pub(crate) fn apply_all_diff_hunks(
17921        &mut self,
17922        _: &ApplyAllDiffHunks,
17923        window: &mut Window,
17924        cx: &mut Context<Self>,
17925    ) {
17926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17927
17928        let buffers = self.buffer.read(cx).all_buffers();
17929        for branch_buffer in buffers {
17930            branch_buffer.update(cx, |branch_buffer, cx| {
17931                branch_buffer.merge_into_base(Vec::new(), cx);
17932            });
17933        }
17934
17935        if let Some(project) = self.project.clone() {
17936            self.save(
17937                SaveOptions {
17938                    format: true,
17939                    autosave: false,
17940                },
17941                project,
17942                window,
17943                cx,
17944            )
17945            .detach_and_log_err(cx);
17946        }
17947    }
17948
17949    pub(crate) fn apply_selected_diff_hunks(
17950        &mut self,
17951        _: &ApplyDiffHunk,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17956        let snapshot = self.snapshot(window, cx);
17957        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17958        let mut ranges_by_buffer = HashMap::default();
17959        self.transact(window, cx, |editor, _window, cx| {
17960            for hunk in hunks {
17961                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17962                    ranges_by_buffer
17963                        .entry(buffer.clone())
17964                        .or_insert_with(Vec::new)
17965                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17966                }
17967            }
17968
17969            for (buffer, ranges) in ranges_by_buffer {
17970                buffer.update(cx, |buffer, cx| {
17971                    buffer.merge_into_base(ranges, cx);
17972                });
17973            }
17974        });
17975
17976        if let Some(project) = self.project.clone() {
17977            self.save(
17978                SaveOptions {
17979                    format: true,
17980                    autosave: false,
17981                },
17982                project,
17983                window,
17984                cx,
17985            )
17986            .detach_and_log_err(cx);
17987        }
17988    }
17989
17990    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17991        if hovered != self.gutter_hovered {
17992            self.gutter_hovered = hovered;
17993            cx.notify();
17994        }
17995    }
17996
17997    pub fn insert_blocks(
17998        &mut self,
17999        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18000        autoscroll: Option<Autoscroll>,
18001        cx: &mut Context<Self>,
18002    ) -> Vec<CustomBlockId> {
18003        let blocks = self
18004            .display_map
18005            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18006        if let Some(autoscroll) = autoscroll {
18007            self.request_autoscroll(autoscroll, cx);
18008        }
18009        cx.notify();
18010        blocks
18011    }
18012
18013    pub fn resize_blocks(
18014        &mut self,
18015        heights: HashMap<CustomBlockId, u32>,
18016        autoscroll: Option<Autoscroll>,
18017        cx: &mut Context<Self>,
18018    ) {
18019        self.display_map
18020            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18021        if let Some(autoscroll) = autoscroll {
18022            self.request_autoscroll(autoscroll, cx);
18023        }
18024        cx.notify();
18025    }
18026
18027    pub fn replace_blocks(
18028        &mut self,
18029        renderers: HashMap<CustomBlockId, RenderBlock>,
18030        autoscroll: Option<Autoscroll>,
18031        cx: &mut Context<Self>,
18032    ) {
18033        self.display_map
18034            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18035        if let Some(autoscroll) = autoscroll {
18036            self.request_autoscroll(autoscroll, cx);
18037        }
18038        cx.notify();
18039    }
18040
18041    pub fn remove_blocks(
18042        &mut self,
18043        block_ids: HashSet<CustomBlockId>,
18044        autoscroll: Option<Autoscroll>,
18045        cx: &mut Context<Self>,
18046    ) {
18047        self.display_map.update(cx, |display_map, cx| {
18048            display_map.remove_blocks(block_ids, cx)
18049        });
18050        if let Some(autoscroll) = autoscroll {
18051            self.request_autoscroll(autoscroll, cx);
18052        }
18053        cx.notify();
18054    }
18055
18056    pub fn row_for_block(
18057        &self,
18058        block_id: CustomBlockId,
18059        cx: &mut Context<Self>,
18060    ) -> Option<DisplayRow> {
18061        self.display_map
18062            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18063    }
18064
18065    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18066        self.focused_block = Some(focused_block);
18067    }
18068
18069    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18070        self.focused_block.take()
18071    }
18072
18073    pub fn insert_creases(
18074        &mut self,
18075        creases: impl IntoIterator<Item = Crease<Anchor>>,
18076        cx: &mut Context<Self>,
18077    ) -> Vec<CreaseId> {
18078        self.display_map
18079            .update(cx, |map, cx| map.insert_creases(creases, cx))
18080    }
18081
18082    pub fn remove_creases(
18083        &mut self,
18084        ids: impl IntoIterator<Item = CreaseId>,
18085        cx: &mut Context<Self>,
18086    ) -> Vec<(CreaseId, Range<Anchor>)> {
18087        self.display_map
18088            .update(cx, |map, cx| map.remove_creases(ids, cx))
18089    }
18090
18091    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18092        self.display_map
18093            .update(cx, |map, cx| map.snapshot(cx))
18094            .longest_row()
18095    }
18096
18097    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18098        self.display_map
18099            .update(cx, |map, cx| map.snapshot(cx))
18100            .max_point()
18101    }
18102
18103    pub fn text(&self, cx: &App) -> String {
18104        self.buffer.read(cx).read(cx).text()
18105    }
18106
18107    pub fn is_empty(&self, cx: &App) -> bool {
18108        self.buffer.read(cx).read(cx).is_empty()
18109    }
18110
18111    pub fn text_option(&self, cx: &App) -> Option<String> {
18112        let text = self.text(cx);
18113        let text = text.trim();
18114
18115        if text.is_empty() {
18116            return None;
18117        }
18118
18119        Some(text.to_string())
18120    }
18121
18122    pub fn set_text(
18123        &mut self,
18124        text: impl Into<Arc<str>>,
18125        window: &mut Window,
18126        cx: &mut Context<Self>,
18127    ) {
18128        self.transact(window, cx, |this, _, cx| {
18129            this.buffer
18130                .read(cx)
18131                .as_singleton()
18132                .expect("you can only call set_text on editors for singleton buffers")
18133                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18134        });
18135    }
18136
18137    pub fn display_text(&self, cx: &mut App) -> String {
18138        self.display_map
18139            .update(cx, |map, cx| map.snapshot(cx))
18140            .text()
18141    }
18142
18143    fn create_minimap(
18144        &self,
18145        minimap_settings: MinimapSettings,
18146        window: &mut Window,
18147        cx: &mut Context<Self>,
18148    ) -> Option<Entity<Self>> {
18149        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18150            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18151    }
18152
18153    fn initialize_new_minimap(
18154        &self,
18155        minimap_settings: MinimapSettings,
18156        window: &mut Window,
18157        cx: &mut Context<Self>,
18158    ) -> Entity<Self> {
18159        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18160
18161        let mut minimap = Editor::new_internal(
18162            EditorMode::Minimap {
18163                parent: cx.weak_entity(),
18164            },
18165            self.buffer.clone(),
18166            None,
18167            Some(self.display_map.clone()),
18168            window,
18169            cx,
18170        );
18171        minimap.scroll_manager.clone_state(&self.scroll_manager);
18172        minimap.set_text_style_refinement(TextStyleRefinement {
18173            font_size: Some(MINIMAP_FONT_SIZE),
18174            font_weight: Some(MINIMAP_FONT_WEIGHT),
18175            ..Default::default()
18176        });
18177        minimap.update_minimap_configuration(minimap_settings, cx);
18178        cx.new(|_| minimap)
18179    }
18180
18181    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18182        let current_line_highlight = minimap_settings
18183            .current_line_highlight
18184            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18185        self.set_current_line_highlight(Some(current_line_highlight));
18186    }
18187
18188    pub fn minimap(&self) -> Option<&Entity<Self>> {
18189        self.minimap
18190            .as_ref()
18191            .filter(|_| self.minimap_visibility.visible())
18192    }
18193
18194    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18195        let mut wrap_guides = smallvec![];
18196
18197        if self.show_wrap_guides == Some(false) {
18198            return wrap_guides;
18199        }
18200
18201        let settings = self.buffer.read(cx).language_settings(cx);
18202        if settings.show_wrap_guides {
18203            match self.soft_wrap_mode(cx) {
18204                SoftWrap::Column(soft_wrap) => {
18205                    wrap_guides.push((soft_wrap as usize, true));
18206                }
18207                SoftWrap::Bounded(soft_wrap) => {
18208                    wrap_guides.push((soft_wrap as usize, true));
18209                }
18210                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18211            }
18212            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18213        }
18214
18215        wrap_guides
18216    }
18217
18218    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18219        let settings = self.buffer.read(cx).language_settings(cx);
18220        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18221        match mode {
18222            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18223                SoftWrap::None
18224            }
18225            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18226            language_settings::SoftWrap::PreferredLineLength => {
18227                SoftWrap::Column(settings.preferred_line_length)
18228            }
18229            language_settings::SoftWrap::Bounded => {
18230                SoftWrap::Bounded(settings.preferred_line_length)
18231            }
18232        }
18233    }
18234
18235    pub fn set_soft_wrap_mode(
18236        &mut self,
18237        mode: language_settings::SoftWrap,
18238
18239        cx: &mut Context<Self>,
18240    ) {
18241        self.soft_wrap_mode_override = Some(mode);
18242        cx.notify();
18243    }
18244
18245    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18246        self.hard_wrap = hard_wrap;
18247        cx.notify();
18248    }
18249
18250    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18251        self.text_style_refinement = Some(style);
18252    }
18253
18254    /// called by the Element so we know what style we were most recently rendered with.
18255    pub(crate) fn set_style(
18256        &mut self,
18257        style: EditorStyle,
18258        window: &mut Window,
18259        cx: &mut Context<Self>,
18260    ) {
18261        // We intentionally do not inform the display map about the minimap style
18262        // so that wrapping is not recalculated and stays consistent for the editor
18263        // and its linked minimap.
18264        if !self.mode.is_minimap() {
18265            let rem_size = window.rem_size();
18266            self.display_map.update(cx, |map, cx| {
18267                map.set_font(
18268                    style.text.font(),
18269                    style.text.font_size.to_pixels(rem_size),
18270                    cx,
18271                )
18272            });
18273        }
18274        self.style = Some(style);
18275    }
18276
18277    pub fn style(&self) -> Option<&EditorStyle> {
18278        self.style.as_ref()
18279    }
18280
18281    // Called by the element. This method is not designed to be called outside of the editor
18282    // element's layout code because it does not notify when rewrapping is computed synchronously.
18283    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18284        self.display_map
18285            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18286    }
18287
18288    pub fn set_soft_wrap(&mut self) {
18289        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18290    }
18291
18292    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18293        if self.soft_wrap_mode_override.is_some() {
18294            self.soft_wrap_mode_override.take();
18295        } else {
18296            let soft_wrap = match self.soft_wrap_mode(cx) {
18297                SoftWrap::GitDiff => return,
18298                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18299                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18300                    language_settings::SoftWrap::None
18301                }
18302            };
18303            self.soft_wrap_mode_override = Some(soft_wrap);
18304        }
18305        cx.notify();
18306    }
18307
18308    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18309        let Some(workspace) = self.workspace() else {
18310            return;
18311        };
18312        let fs = workspace.read(cx).app_state().fs.clone();
18313        let current_show = TabBarSettings::get_global(cx).show;
18314        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18315            setting.show = Some(!current_show);
18316        });
18317    }
18318
18319    pub fn toggle_indent_guides(
18320        &mut self,
18321        _: &ToggleIndentGuides,
18322        _: &mut Window,
18323        cx: &mut Context<Self>,
18324    ) {
18325        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18326            self.buffer
18327                .read(cx)
18328                .language_settings(cx)
18329                .indent_guides
18330                .enabled
18331        });
18332        self.show_indent_guides = Some(!currently_enabled);
18333        cx.notify();
18334    }
18335
18336    fn should_show_indent_guides(&self) -> Option<bool> {
18337        self.show_indent_guides
18338    }
18339
18340    pub fn toggle_line_numbers(
18341        &mut self,
18342        _: &ToggleLineNumbers,
18343        _: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        let mut editor_settings = EditorSettings::get_global(cx).clone();
18347        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18348        EditorSettings::override_global(editor_settings, cx);
18349    }
18350
18351    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18352        if let Some(show_line_numbers) = self.show_line_numbers {
18353            return show_line_numbers;
18354        }
18355        EditorSettings::get_global(cx).gutter.line_numbers
18356    }
18357
18358    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18359        self.use_relative_line_numbers
18360            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18361    }
18362
18363    pub fn toggle_relative_line_numbers(
18364        &mut self,
18365        _: &ToggleRelativeLineNumbers,
18366        _: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        let is_relative = self.should_use_relative_line_numbers(cx);
18370        self.set_relative_line_number(Some(!is_relative), cx)
18371    }
18372
18373    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18374        self.use_relative_line_numbers = is_relative;
18375        cx.notify();
18376    }
18377
18378    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18379        self.show_gutter = show_gutter;
18380        cx.notify();
18381    }
18382
18383    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18384        self.show_scrollbars = ScrollbarAxes {
18385            horizontal: show,
18386            vertical: show,
18387        };
18388        cx.notify();
18389    }
18390
18391    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18392        self.show_scrollbars.vertical = show;
18393        cx.notify();
18394    }
18395
18396    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18397        self.show_scrollbars.horizontal = show;
18398        cx.notify();
18399    }
18400
18401    pub fn set_minimap_visibility(
18402        &mut self,
18403        minimap_visibility: MinimapVisibility,
18404        window: &mut Window,
18405        cx: &mut Context<Self>,
18406    ) {
18407        if self.minimap_visibility != minimap_visibility {
18408            if minimap_visibility.visible() && self.minimap.is_none() {
18409                let minimap_settings = EditorSettings::get_global(cx).minimap;
18410                self.minimap =
18411                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18412            }
18413            self.minimap_visibility = minimap_visibility;
18414            cx.notify();
18415        }
18416    }
18417
18418    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18419        self.set_show_scrollbars(false, cx);
18420        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18421    }
18422
18423    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18424        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18425    }
18426
18427    /// Normally the text in full mode and auto height editors is padded on the
18428    /// left side by roughly half a character width for improved hit testing.
18429    ///
18430    /// Use this method to disable this for cases where this is not wanted (e.g.
18431    /// if you want to align the editor text with some other text above or below)
18432    /// or if you want to add this padding to single-line editors.
18433    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18434        self.offset_content = offset_content;
18435        cx.notify();
18436    }
18437
18438    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18439        self.show_line_numbers = Some(show_line_numbers);
18440        cx.notify();
18441    }
18442
18443    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18444        self.disable_expand_excerpt_buttons = true;
18445        cx.notify();
18446    }
18447
18448    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18449        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18450        cx.notify();
18451    }
18452
18453    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18454        self.show_code_actions = Some(show_code_actions);
18455        cx.notify();
18456    }
18457
18458    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18459        self.show_runnables = Some(show_runnables);
18460        cx.notify();
18461    }
18462
18463    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18464        self.show_breakpoints = Some(show_breakpoints);
18465        cx.notify();
18466    }
18467
18468    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18469        if self.display_map.read(cx).masked != masked {
18470            self.display_map.update(cx, |map, _| map.masked = masked);
18471        }
18472        cx.notify()
18473    }
18474
18475    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18476        self.show_wrap_guides = Some(show_wrap_guides);
18477        cx.notify();
18478    }
18479
18480    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18481        self.show_indent_guides = Some(show_indent_guides);
18482        cx.notify();
18483    }
18484
18485    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18486        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18487            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18488                if let Some(dir) = file.abs_path(cx).parent() {
18489                    return Some(dir.to_owned());
18490                }
18491            }
18492
18493            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18494                return Some(project_path.path.to_path_buf());
18495            }
18496        }
18497
18498        None
18499    }
18500
18501    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18502        self.active_excerpt(cx)?
18503            .1
18504            .read(cx)
18505            .file()
18506            .and_then(|f| f.as_local())
18507    }
18508
18509    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18510        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18511            let buffer = buffer.read(cx);
18512            if let Some(project_path) = buffer.project_path(cx) {
18513                let project = self.project.as_ref()?.read(cx);
18514                project.absolute_path(&project_path, cx)
18515            } else {
18516                buffer
18517                    .file()
18518                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18519            }
18520        })
18521    }
18522
18523    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18524        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18525            let project_path = buffer.read(cx).project_path(cx)?;
18526            let project = self.project.as_ref()?.read(cx);
18527            let entry = project.entry_for_path(&project_path, cx)?;
18528            let path = entry.path.to_path_buf();
18529            Some(path)
18530        })
18531    }
18532
18533    pub fn reveal_in_finder(
18534        &mut self,
18535        _: &RevealInFileManager,
18536        _window: &mut Window,
18537        cx: &mut Context<Self>,
18538    ) {
18539        if let Some(target) = self.target_file(cx) {
18540            cx.reveal_path(&target.abs_path(cx));
18541        }
18542    }
18543
18544    pub fn copy_path(
18545        &mut self,
18546        _: &zed_actions::workspace::CopyPath,
18547        _window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        if let Some(path) = self.target_file_abs_path(cx) {
18551            if let Some(path) = path.to_str() {
18552                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18553            }
18554        }
18555    }
18556
18557    pub fn copy_relative_path(
18558        &mut self,
18559        _: &zed_actions::workspace::CopyRelativePath,
18560        _window: &mut Window,
18561        cx: &mut Context<Self>,
18562    ) {
18563        if let Some(path) = self.target_file_path(cx) {
18564            if let Some(path) = path.to_str() {
18565                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18566            }
18567        }
18568    }
18569
18570    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18571        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18572            buffer.read(cx).project_path(cx)
18573        } else {
18574            None
18575        }
18576    }
18577
18578    // Returns true if the editor handled a go-to-line request
18579    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18580        maybe!({
18581            let breakpoint_store = self.breakpoint_store.as_ref()?;
18582
18583            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18584            else {
18585                self.clear_row_highlights::<ActiveDebugLine>();
18586                return None;
18587            };
18588
18589            let position = active_stack_frame.position;
18590            let buffer_id = position.buffer_id?;
18591            let snapshot = self
18592                .project
18593                .as_ref()?
18594                .read(cx)
18595                .buffer_for_id(buffer_id, cx)?
18596                .read(cx)
18597                .snapshot();
18598
18599            let mut handled = false;
18600            for (id, ExcerptRange { context, .. }) in
18601                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18602            {
18603                if context.start.cmp(&position, &snapshot).is_ge()
18604                    || context.end.cmp(&position, &snapshot).is_lt()
18605                {
18606                    continue;
18607                }
18608                let snapshot = self.buffer.read(cx).snapshot(cx);
18609                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18610
18611                handled = true;
18612                self.clear_row_highlights::<ActiveDebugLine>();
18613
18614                self.go_to_line::<ActiveDebugLine>(
18615                    multibuffer_anchor,
18616                    Some(cx.theme().colors().editor_debugger_active_line_background),
18617                    window,
18618                    cx,
18619                );
18620
18621                cx.notify();
18622            }
18623
18624            handled.then_some(())
18625        })
18626        .is_some()
18627    }
18628
18629    pub fn copy_file_name_without_extension(
18630        &mut self,
18631        _: &CopyFileNameWithoutExtension,
18632        _: &mut Window,
18633        cx: &mut Context<Self>,
18634    ) {
18635        if let Some(file) = self.target_file(cx) {
18636            if let Some(file_stem) = file.path().file_stem() {
18637                if let Some(name) = file_stem.to_str() {
18638                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18639                }
18640            }
18641        }
18642    }
18643
18644    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18645        if let Some(file) = self.target_file(cx) {
18646            if let Some(file_name) = file.path().file_name() {
18647                if let Some(name) = file_name.to_str() {
18648                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18649                }
18650            }
18651        }
18652    }
18653
18654    pub fn toggle_git_blame(
18655        &mut self,
18656        _: &::git::Blame,
18657        window: &mut Window,
18658        cx: &mut Context<Self>,
18659    ) {
18660        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18661
18662        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18663            self.start_git_blame(true, window, cx);
18664        }
18665
18666        cx.notify();
18667    }
18668
18669    pub fn toggle_git_blame_inline(
18670        &mut self,
18671        _: &ToggleGitBlameInline,
18672        window: &mut Window,
18673        cx: &mut Context<Self>,
18674    ) {
18675        self.toggle_git_blame_inline_internal(true, window, cx);
18676        cx.notify();
18677    }
18678
18679    pub fn open_git_blame_commit(
18680        &mut self,
18681        _: &OpenGitBlameCommit,
18682        window: &mut Window,
18683        cx: &mut Context<Self>,
18684    ) {
18685        self.open_git_blame_commit_internal(window, cx);
18686    }
18687
18688    fn open_git_blame_commit_internal(
18689        &mut self,
18690        window: &mut Window,
18691        cx: &mut Context<Self>,
18692    ) -> Option<()> {
18693        let blame = self.blame.as_ref()?;
18694        let snapshot = self.snapshot(window, cx);
18695        let cursor = self.selections.newest::<Point>(cx).head();
18696        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18697        let blame_entry = blame
18698            .update(cx, |blame, cx| {
18699                blame
18700                    .blame_for_rows(
18701                        &[RowInfo {
18702                            buffer_id: Some(buffer.remote_id()),
18703                            buffer_row: Some(point.row),
18704                            ..Default::default()
18705                        }],
18706                        cx,
18707                    )
18708                    .next()
18709            })
18710            .flatten()?;
18711        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18712        let repo = blame.read(cx).repository(cx)?;
18713        let workspace = self.workspace()?.downgrade();
18714        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18715        None
18716    }
18717
18718    pub fn git_blame_inline_enabled(&self) -> bool {
18719        self.git_blame_inline_enabled
18720    }
18721
18722    pub fn toggle_selection_menu(
18723        &mut self,
18724        _: &ToggleSelectionMenu,
18725        _: &mut Window,
18726        cx: &mut Context<Self>,
18727    ) {
18728        self.show_selection_menu = self
18729            .show_selection_menu
18730            .map(|show_selections_menu| !show_selections_menu)
18731            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18732
18733        cx.notify();
18734    }
18735
18736    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18737        self.show_selection_menu
18738            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18739    }
18740
18741    fn start_git_blame(
18742        &mut self,
18743        user_triggered: bool,
18744        window: &mut Window,
18745        cx: &mut Context<Self>,
18746    ) {
18747        if let Some(project) = self.project.as_ref() {
18748            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18749                return;
18750            };
18751
18752            if buffer.read(cx).file().is_none() {
18753                return;
18754            }
18755
18756            let focused = self.focus_handle(cx).contains_focused(window, cx);
18757
18758            let project = project.clone();
18759            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18760            self.blame_subscription =
18761                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18762            self.blame = Some(blame);
18763        }
18764    }
18765
18766    fn toggle_git_blame_inline_internal(
18767        &mut self,
18768        user_triggered: bool,
18769        window: &mut Window,
18770        cx: &mut Context<Self>,
18771    ) {
18772        if self.git_blame_inline_enabled {
18773            self.git_blame_inline_enabled = false;
18774            self.show_git_blame_inline = false;
18775            self.show_git_blame_inline_delay_task.take();
18776        } else {
18777            self.git_blame_inline_enabled = true;
18778            self.start_git_blame_inline(user_triggered, window, cx);
18779        }
18780
18781        cx.notify();
18782    }
18783
18784    fn start_git_blame_inline(
18785        &mut self,
18786        user_triggered: bool,
18787        window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        self.start_git_blame(user_triggered, window, cx);
18791
18792        if ProjectSettings::get_global(cx)
18793            .git
18794            .inline_blame_delay()
18795            .is_some()
18796        {
18797            self.start_inline_blame_timer(window, cx);
18798        } else {
18799            self.show_git_blame_inline = true
18800        }
18801    }
18802
18803    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18804        self.blame.as_ref()
18805    }
18806
18807    pub fn show_git_blame_gutter(&self) -> bool {
18808        self.show_git_blame_gutter
18809    }
18810
18811    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18812        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18813    }
18814
18815    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18816        self.show_git_blame_inline
18817            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18818            && !self.newest_selection_head_on_empty_line(cx)
18819            && self.has_blame_entries(cx)
18820    }
18821
18822    fn has_blame_entries(&self, cx: &App) -> bool {
18823        self.blame()
18824            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18825    }
18826
18827    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18828        let cursor_anchor = self.selections.newest_anchor().head();
18829
18830        let snapshot = self.buffer.read(cx).snapshot(cx);
18831        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18832
18833        snapshot.line_len(buffer_row) == 0
18834    }
18835
18836    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18837        let buffer_and_selection = maybe!({
18838            let selection = self.selections.newest::<Point>(cx);
18839            let selection_range = selection.range();
18840
18841            let multi_buffer = self.buffer().read(cx);
18842            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18843            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18844
18845            let (buffer, range, _) = if selection.reversed {
18846                buffer_ranges.first()
18847            } else {
18848                buffer_ranges.last()
18849            }?;
18850
18851            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18852                ..text::ToPoint::to_point(&range.end, &buffer).row;
18853            Some((
18854                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18855                selection,
18856            ))
18857        });
18858
18859        let Some((buffer, selection)) = buffer_and_selection else {
18860            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18861        };
18862
18863        let Some(project) = self.project.as_ref() else {
18864            return Task::ready(Err(anyhow!("editor does not have project")));
18865        };
18866
18867        project.update(cx, |project, cx| {
18868            project.get_permalink_to_line(&buffer, selection, cx)
18869        })
18870    }
18871
18872    pub fn copy_permalink_to_line(
18873        &mut self,
18874        _: &CopyPermalinkToLine,
18875        window: &mut Window,
18876        cx: &mut Context<Self>,
18877    ) {
18878        let permalink_task = self.get_permalink_to_line(cx);
18879        let workspace = self.workspace();
18880
18881        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18882            Ok(permalink) => {
18883                cx.update(|_, cx| {
18884                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18885                })
18886                .ok();
18887            }
18888            Err(err) => {
18889                let message = format!("Failed to copy permalink: {err}");
18890
18891                anyhow::Result::<()>::Err(err).log_err();
18892
18893                if let Some(workspace) = workspace {
18894                    workspace
18895                        .update_in(cx, |workspace, _, cx| {
18896                            struct CopyPermalinkToLine;
18897
18898                            workspace.show_toast(
18899                                Toast::new(
18900                                    NotificationId::unique::<CopyPermalinkToLine>(),
18901                                    message,
18902                                ),
18903                                cx,
18904                            )
18905                        })
18906                        .ok();
18907                }
18908            }
18909        })
18910        .detach();
18911    }
18912
18913    pub fn copy_file_location(
18914        &mut self,
18915        _: &CopyFileLocation,
18916        _: &mut Window,
18917        cx: &mut Context<Self>,
18918    ) {
18919        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18920        if let Some(file) = self.target_file(cx) {
18921            if let Some(path) = file.path().to_str() {
18922                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18923            }
18924        }
18925    }
18926
18927    pub fn open_permalink_to_line(
18928        &mut self,
18929        _: &OpenPermalinkToLine,
18930        window: &mut Window,
18931        cx: &mut Context<Self>,
18932    ) {
18933        let permalink_task = self.get_permalink_to_line(cx);
18934        let workspace = self.workspace();
18935
18936        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18937            Ok(permalink) => {
18938                cx.update(|_, cx| {
18939                    cx.open_url(permalink.as_ref());
18940                })
18941                .ok();
18942            }
18943            Err(err) => {
18944                let message = format!("Failed to open permalink: {err}");
18945
18946                anyhow::Result::<()>::Err(err).log_err();
18947
18948                if let Some(workspace) = workspace {
18949                    workspace
18950                        .update(cx, |workspace, cx| {
18951                            struct OpenPermalinkToLine;
18952
18953                            workspace.show_toast(
18954                                Toast::new(
18955                                    NotificationId::unique::<OpenPermalinkToLine>(),
18956                                    message,
18957                                ),
18958                                cx,
18959                            )
18960                        })
18961                        .ok();
18962                }
18963            }
18964        })
18965        .detach();
18966    }
18967
18968    pub fn insert_uuid_v4(
18969        &mut self,
18970        _: &InsertUuidV4,
18971        window: &mut Window,
18972        cx: &mut Context<Self>,
18973    ) {
18974        self.insert_uuid(UuidVersion::V4, window, cx);
18975    }
18976
18977    pub fn insert_uuid_v7(
18978        &mut self,
18979        _: &InsertUuidV7,
18980        window: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        self.insert_uuid(UuidVersion::V7, window, cx);
18984    }
18985
18986    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18988        self.transact(window, cx, |this, window, cx| {
18989            let edits = this
18990                .selections
18991                .all::<Point>(cx)
18992                .into_iter()
18993                .map(|selection| {
18994                    let uuid = match version {
18995                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18996                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18997                    };
18998
18999                    (selection.range(), uuid.to_string())
19000                });
19001            this.edit(edits, cx);
19002            this.refresh_inline_completion(true, false, window, cx);
19003        });
19004    }
19005
19006    pub fn open_selections_in_multibuffer(
19007        &mut self,
19008        _: &OpenSelectionsInMultibuffer,
19009        window: &mut Window,
19010        cx: &mut Context<Self>,
19011    ) {
19012        let multibuffer = self.buffer.read(cx);
19013
19014        let Some(buffer) = multibuffer.as_singleton() else {
19015            return;
19016        };
19017
19018        let Some(workspace) = self.workspace() else {
19019            return;
19020        };
19021
19022        let title = multibuffer.title(cx).to_string();
19023
19024        let locations = self
19025            .selections
19026            .all_anchors(cx)
19027            .into_iter()
19028            .map(|selection| Location {
19029                buffer: buffer.clone(),
19030                range: selection.start.text_anchor..selection.end.text_anchor,
19031            })
19032            .collect::<Vec<_>>();
19033
19034        cx.spawn_in(window, async move |_, cx| {
19035            workspace.update_in(cx, |workspace, window, cx| {
19036                Self::open_locations_in_multibuffer(
19037                    workspace,
19038                    locations,
19039                    format!("Selections for '{title}'"),
19040                    false,
19041                    MultibufferSelectionMode::All,
19042                    window,
19043                    cx,
19044                );
19045            })
19046        })
19047        .detach();
19048    }
19049
19050    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19051    /// last highlight added will be used.
19052    ///
19053    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19054    pub fn highlight_rows<T: 'static>(
19055        &mut self,
19056        range: Range<Anchor>,
19057        color: Hsla,
19058        options: RowHighlightOptions,
19059        cx: &mut Context<Self>,
19060    ) {
19061        let snapshot = self.buffer().read(cx).snapshot(cx);
19062        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19063        let ix = row_highlights.binary_search_by(|highlight| {
19064            Ordering::Equal
19065                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19066                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19067        });
19068
19069        if let Err(mut ix) = ix {
19070            let index = post_inc(&mut self.highlight_order);
19071
19072            // If this range intersects with the preceding highlight, then merge it with
19073            // the preceding highlight. Otherwise insert a new highlight.
19074            let mut merged = false;
19075            if ix > 0 {
19076                let prev_highlight = &mut row_highlights[ix - 1];
19077                if prev_highlight
19078                    .range
19079                    .end
19080                    .cmp(&range.start, &snapshot)
19081                    .is_ge()
19082                {
19083                    ix -= 1;
19084                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19085                        prev_highlight.range.end = range.end;
19086                    }
19087                    merged = true;
19088                    prev_highlight.index = index;
19089                    prev_highlight.color = color;
19090                    prev_highlight.options = options;
19091                }
19092            }
19093
19094            if !merged {
19095                row_highlights.insert(
19096                    ix,
19097                    RowHighlight {
19098                        range: range.clone(),
19099                        index,
19100                        color,
19101                        options,
19102                        type_id: TypeId::of::<T>(),
19103                    },
19104                );
19105            }
19106
19107            // If any of the following highlights intersect with this one, merge them.
19108            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19109                let highlight = &row_highlights[ix];
19110                if next_highlight
19111                    .range
19112                    .start
19113                    .cmp(&highlight.range.end, &snapshot)
19114                    .is_le()
19115                {
19116                    if next_highlight
19117                        .range
19118                        .end
19119                        .cmp(&highlight.range.end, &snapshot)
19120                        .is_gt()
19121                    {
19122                        row_highlights[ix].range.end = next_highlight.range.end;
19123                    }
19124                    row_highlights.remove(ix + 1);
19125                } else {
19126                    break;
19127                }
19128            }
19129        }
19130    }
19131
19132    /// Remove any highlighted row ranges of the given type that intersect the
19133    /// given ranges.
19134    pub fn remove_highlighted_rows<T: 'static>(
19135        &mut self,
19136        ranges_to_remove: Vec<Range<Anchor>>,
19137        cx: &mut Context<Self>,
19138    ) {
19139        let snapshot = self.buffer().read(cx).snapshot(cx);
19140        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19141        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19142        row_highlights.retain(|highlight| {
19143            while let Some(range_to_remove) = ranges_to_remove.peek() {
19144                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19145                    Ordering::Less | Ordering::Equal => {
19146                        ranges_to_remove.next();
19147                    }
19148                    Ordering::Greater => {
19149                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19150                            Ordering::Less | Ordering::Equal => {
19151                                return false;
19152                            }
19153                            Ordering::Greater => break,
19154                        }
19155                    }
19156                }
19157            }
19158
19159            true
19160        })
19161    }
19162
19163    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19164    pub fn clear_row_highlights<T: 'static>(&mut self) {
19165        self.highlighted_rows.remove(&TypeId::of::<T>());
19166    }
19167
19168    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19169    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19170        self.highlighted_rows
19171            .get(&TypeId::of::<T>())
19172            .map_or(&[] as &[_], |vec| vec.as_slice())
19173            .iter()
19174            .map(|highlight| (highlight.range.clone(), highlight.color))
19175    }
19176
19177    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19178    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19179    /// Allows to ignore certain kinds of highlights.
19180    pub fn highlighted_display_rows(
19181        &self,
19182        window: &mut Window,
19183        cx: &mut App,
19184    ) -> BTreeMap<DisplayRow, LineHighlight> {
19185        let snapshot = self.snapshot(window, cx);
19186        let mut used_highlight_orders = HashMap::default();
19187        self.highlighted_rows
19188            .iter()
19189            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19190            .fold(
19191                BTreeMap::<DisplayRow, LineHighlight>::new(),
19192                |mut unique_rows, highlight| {
19193                    let start = highlight.range.start.to_display_point(&snapshot);
19194                    let end = highlight.range.end.to_display_point(&snapshot);
19195                    let start_row = start.row().0;
19196                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19197                        && end.column() == 0
19198                    {
19199                        end.row().0.saturating_sub(1)
19200                    } else {
19201                        end.row().0
19202                    };
19203                    for row in start_row..=end_row {
19204                        let used_index =
19205                            used_highlight_orders.entry(row).or_insert(highlight.index);
19206                        if highlight.index >= *used_index {
19207                            *used_index = highlight.index;
19208                            unique_rows.insert(
19209                                DisplayRow(row),
19210                                LineHighlight {
19211                                    include_gutter: highlight.options.include_gutter,
19212                                    border: None,
19213                                    background: highlight.color.into(),
19214                                    type_id: Some(highlight.type_id),
19215                                },
19216                            );
19217                        }
19218                    }
19219                    unique_rows
19220                },
19221            )
19222    }
19223
19224    pub fn highlighted_display_row_for_autoscroll(
19225        &self,
19226        snapshot: &DisplaySnapshot,
19227    ) -> Option<DisplayRow> {
19228        self.highlighted_rows
19229            .values()
19230            .flat_map(|highlighted_rows| highlighted_rows.iter())
19231            .filter_map(|highlight| {
19232                if highlight.options.autoscroll {
19233                    Some(highlight.range.start.to_display_point(snapshot).row())
19234                } else {
19235                    None
19236                }
19237            })
19238            .min()
19239    }
19240
19241    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19242        self.highlight_background::<SearchWithinRange>(
19243            ranges,
19244            |colors| colors.colors().editor_document_highlight_read_background,
19245            cx,
19246        )
19247    }
19248
19249    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19250        self.breadcrumb_header = Some(new_header);
19251    }
19252
19253    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19254        self.clear_background_highlights::<SearchWithinRange>(cx);
19255    }
19256
19257    pub fn highlight_background<T: 'static>(
19258        &mut self,
19259        ranges: &[Range<Anchor>],
19260        color_fetcher: fn(&Theme) -> Hsla,
19261        cx: &mut Context<Self>,
19262    ) {
19263        self.background_highlights.insert(
19264            HighlightKey::Type(TypeId::of::<T>()),
19265            (color_fetcher, Arc::from(ranges)),
19266        );
19267        self.scrollbar_marker_state.dirty = true;
19268        cx.notify();
19269    }
19270
19271    pub fn highlight_background_key<T: 'static>(
19272        &mut self,
19273        key: usize,
19274        ranges: &[Range<Anchor>],
19275        color_fetcher: fn(&Theme) -> Hsla,
19276        cx: &mut Context<Self>,
19277    ) {
19278        self.background_highlights.insert(
19279            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19280            (color_fetcher, Arc::from(ranges)),
19281        );
19282        self.scrollbar_marker_state.dirty = true;
19283        cx.notify();
19284    }
19285
19286    pub fn clear_background_highlights<T: 'static>(
19287        &mut self,
19288        cx: &mut Context<Self>,
19289    ) -> Option<BackgroundHighlight> {
19290        let text_highlights = self
19291            .background_highlights
19292            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19293        if !text_highlights.1.is_empty() {
19294            self.scrollbar_marker_state.dirty = true;
19295            cx.notify();
19296        }
19297        Some(text_highlights)
19298    }
19299
19300    pub fn highlight_gutter<T: 'static>(
19301        &mut self,
19302        ranges: impl Into<Vec<Range<Anchor>>>,
19303        color_fetcher: fn(&App) -> Hsla,
19304        cx: &mut Context<Self>,
19305    ) {
19306        self.gutter_highlights
19307            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19308        cx.notify();
19309    }
19310
19311    pub fn clear_gutter_highlights<T: 'static>(
19312        &mut self,
19313        cx: &mut Context<Self>,
19314    ) -> Option<GutterHighlight> {
19315        cx.notify();
19316        self.gutter_highlights.remove(&TypeId::of::<T>())
19317    }
19318
19319    pub fn insert_gutter_highlight<T: 'static>(
19320        &mut self,
19321        range: Range<Anchor>,
19322        color_fetcher: fn(&App) -> Hsla,
19323        cx: &mut Context<Self>,
19324    ) {
19325        let snapshot = self.buffer().read(cx).snapshot(cx);
19326        let mut highlights = self
19327            .gutter_highlights
19328            .remove(&TypeId::of::<T>())
19329            .map(|(_, highlights)| highlights)
19330            .unwrap_or_default();
19331        let ix = highlights.binary_search_by(|highlight| {
19332            Ordering::Equal
19333                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19334                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19335        });
19336        if let Err(ix) = ix {
19337            highlights.insert(ix, range);
19338        }
19339        self.gutter_highlights
19340            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19341    }
19342
19343    pub fn remove_gutter_highlights<T: 'static>(
19344        &mut self,
19345        ranges_to_remove: Vec<Range<Anchor>>,
19346        cx: &mut Context<Self>,
19347    ) {
19348        let snapshot = self.buffer().read(cx).snapshot(cx);
19349        let Some((color_fetcher, mut gutter_highlights)) =
19350            self.gutter_highlights.remove(&TypeId::of::<T>())
19351        else {
19352            return;
19353        };
19354        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19355        gutter_highlights.retain(|highlight| {
19356            while let Some(range_to_remove) = ranges_to_remove.peek() {
19357                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19358                    Ordering::Less | Ordering::Equal => {
19359                        ranges_to_remove.next();
19360                    }
19361                    Ordering::Greater => {
19362                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19363                            Ordering::Less | Ordering::Equal => {
19364                                return false;
19365                            }
19366                            Ordering::Greater => break,
19367                        }
19368                    }
19369                }
19370            }
19371
19372            true
19373        });
19374        self.gutter_highlights
19375            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19376    }
19377
19378    #[cfg(feature = "test-support")]
19379    pub fn all_text_highlights(
19380        &self,
19381        window: &mut Window,
19382        cx: &mut Context<Self>,
19383    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19384        let snapshot = self.snapshot(window, cx);
19385        self.display_map.update(cx, |display_map, _| {
19386            display_map
19387                .all_text_highlights()
19388                .map(|highlight| {
19389                    let (style, ranges) = highlight.as_ref();
19390                    (
19391                        *style,
19392                        ranges
19393                            .iter()
19394                            .map(|range| range.clone().to_display_points(&snapshot))
19395                            .collect(),
19396                    )
19397                })
19398                .collect()
19399        })
19400    }
19401
19402    #[cfg(feature = "test-support")]
19403    pub fn all_text_background_highlights(
19404        &self,
19405        window: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19408        let snapshot = self.snapshot(window, cx);
19409        let buffer = &snapshot.buffer_snapshot;
19410        let start = buffer.anchor_before(0);
19411        let end = buffer.anchor_after(buffer.len());
19412        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19413    }
19414
19415    #[cfg(feature = "test-support")]
19416    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19417        let snapshot = self.buffer().read(cx).snapshot(cx);
19418
19419        let highlights = self
19420            .background_highlights
19421            .get(&HighlightKey::Type(TypeId::of::<
19422                items::BufferSearchHighlights,
19423            >()));
19424
19425        if let Some((_color, ranges)) = highlights {
19426            ranges
19427                .iter()
19428                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19429                .collect_vec()
19430        } else {
19431            vec![]
19432        }
19433    }
19434
19435    fn document_highlights_for_position<'a>(
19436        &'a self,
19437        position: Anchor,
19438        buffer: &'a MultiBufferSnapshot,
19439    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19440        let read_highlights = self
19441            .background_highlights
19442            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19443            .map(|h| &h.1);
19444        let write_highlights = self
19445            .background_highlights
19446            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19447            .map(|h| &h.1);
19448        let left_position = position.bias_left(buffer);
19449        let right_position = position.bias_right(buffer);
19450        read_highlights
19451            .into_iter()
19452            .chain(write_highlights)
19453            .flat_map(move |ranges| {
19454                let start_ix = match ranges.binary_search_by(|probe| {
19455                    let cmp = probe.end.cmp(&left_position, buffer);
19456                    if cmp.is_ge() {
19457                        Ordering::Greater
19458                    } else {
19459                        Ordering::Less
19460                    }
19461                }) {
19462                    Ok(i) | Err(i) => i,
19463                };
19464
19465                ranges[start_ix..]
19466                    .iter()
19467                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19468            })
19469    }
19470
19471    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19472        self.background_highlights
19473            .get(&HighlightKey::Type(TypeId::of::<T>()))
19474            .map_or(false, |(_, highlights)| !highlights.is_empty())
19475    }
19476
19477    pub fn background_highlights_in_range(
19478        &self,
19479        search_range: Range<Anchor>,
19480        display_snapshot: &DisplaySnapshot,
19481        theme: &Theme,
19482    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19483        let mut results = Vec::new();
19484        for (color_fetcher, ranges) in self.background_highlights.values() {
19485            let color = color_fetcher(theme);
19486            let start_ix = match ranges.binary_search_by(|probe| {
19487                let cmp = probe
19488                    .end
19489                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19490                if cmp.is_gt() {
19491                    Ordering::Greater
19492                } else {
19493                    Ordering::Less
19494                }
19495            }) {
19496                Ok(i) | Err(i) => i,
19497            };
19498            for range in &ranges[start_ix..] {
19499                if range
19500                    .start
19501                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19502                    .is_ge()
19503                {
19504                    break;
19505                }
19506
19507                let start = range.start.to_display_point(display_snapshot);
19508                let end = range.end.to_display_point(display_snapshot);
19509                results.push((start..end, color))
19510            }
19511        }
19512        results
19513    }
19514
19515    pub fn background_highlight_row_ranges<T: 'static>(
19516        &self,
19517        search_range: Range<Anchor>,
19518        display_snapshot: &DisplaySnapshot,
19519        count: usize,
19520    ) -> Vec<RangeInclusive<DisplayPoint>> {
19521        let mut results = Vec::new();
19522        let Some((_, ranges)) = self
19523            .background_highlights
19524            .get(&HighlightKey::Type(TypeId::of::<T>()))
19525        else {
19526            return vec![];
19527        };
19528
19529        let start_ix = match ranges.binary_search_by(|probe| {
19530            let cmp = probe
19531                .end
19532                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19533            if cmp.is_gt() {
19534                Ordering::Greater
19535            } else {
19536                Ordering::Less
19537            }
19538        }) {
19539            Ok(i) | Err(i) => i,
19540        };
19541        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19542            if let (Some(start_display), Some(end_display)) = (start, end) {
19543                results.push(
19544                    start_display.to_display_point(display_snapshot)
19545                        ..=end_display.to_display_point(display_snapshot),
19546                );
19547            }
19548        };
19549        let mut start_row: Option<Point> = None;
19550        let mut end_row: Option<Point> = None;
19551        if ranges.len() > count {
19552            return Vec::new();
19553        }
19554        for range in &ranges[start_ix..] {
19555            if range
19556                .start
19557                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19558                .is_ge()
19559            {
19560                break;
19561            }
19562            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19563            if let Some(current_row) = &end_row {
19564                if end.row == current_row.row {
19565                    continue;
19566                }
19567            }
19568            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19569            if start_row.is_none() {
19570                assert_eq!(end_row, None);
19571                start_row = Some(start);
19572                end_row = Some(end);
19573                continue;
19574            }
19575            if let Some(current_end) = end_row.as_mut() {
19576                if start.row > current_end.row + 1 {
19577                    push_region(start_row, end_row);
19578                    start_row = Some(start);
19579                    end_row = Some(end);
19580                } else {
19581                    // Merge two hunks.
19582                    *current_end = end;
19583                }
19584            } else {
19585                unreachable!();
19586            }
19587        }
19588        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19589        push_region(start_row, end_row);
19590        results
19591    }
19592
19593    pub fn gutter_highlights_in_range(
19594        &self,
19595        search_range: Range<Anchor>,
19596        display_snapshot: &DisplaySnapshot,
19597        cx: &App,
19598    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19599        let mut results = Vec::new();
19600        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19601            let color = color_fetcher(cx);
19602            let start_ix = match ranges.binary_search_by(|probe| {
19603                let cmp = probe
19604                    .end
19605                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19606                if cmp.is_gt() {
19607                    Ordering::Greater
19608                } else {
19609                    Ordering::Less
19610                }
19611            }) {
19612                Ok(i) | Err(i) => i,
19613            };
19614            for range in &ranges[start_ix..] {
19615                if range
19616                    .start
19617                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19618                    .is_ge()
19619                {
19620                    break;
19621                }
19622
19623                let start = range.start.to_display_point(display_snapshot);
19624                let end = range.end.to_display_point(display_snapshot);
19625                results.push((start..end, color))
19626            }
19627        }
19628        results
19629    }
19630
19631    /// Get the text ranges corresponding to the redaction query
19632    pub fn redacted_ranges(
19633        &self,
19634        search_range: Range<Anchor>,
19635        display_snapshot: &DisplaySnapshot,
19636        cx: &App,
19637    ) -> Vec<Range<DisplayPoint>> {
19638        display_snapshot
19639            .buffer_snapshot
19640            .redacted_ranges(search_range, |file| {
19641                if let Some(file) = file {
19642                    file.is_private()
19643                        && EditorSettings::get(
19644                            Some(SettingsLocation {
19645                                worktree_id: file.worktree_id(cx),
19646                                path: file.path().as_ref(),
19647                            }),
19648                            cx,
19649                        )
19650                        .redact_private_values
19651                } else {
19652                    false
19653                }
19654            })
19655            .map(|range| {
19656                range.start.to_display_point(display_snapshot)
19657                    ..range.end.to_display_point(display_snapshot)
19658            })
19659            .collect()
19660    }
19661
19662    pub fn highlight_text_key<T: 'static>(
19663        &mut self,
19664        key: usize,
19665        ranges: Vec<Range<Anchor>>,
19666        style: HighlightStyle,
19667        cx: &mut Context<Self>,
19668    ) {
19669        self.display_map.update(cx, |map, _| {
19670            map.highlight_text(
19671                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19672                ranges,
19673                style,
19674            );
19675        });
19676        cx.notify();
19677    }
19678
19679    pub fn highlight_text<T: 'static>(
19680        &mut self,
19681        ranges: Vec<Range<Anchor>>,
19682        style: HighlightStyle,
19683        cx: &mut Context<Self>,
19684    ) {
19685        self.display_map.update(cx, |map, _| {
19686            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19687        });
19688        cx.notify();
19689    }
19690
19691    pub(crate) fn highlight_inlays<T: 'static>(
19692        &mut self,
19693        highlights: Vec<InlayHighlight>,
19694        style: HighlightStyle,
19695        cx: &mut Context<Self>,
19696    ) {
19697        self.display_map.update(cx, |map, _| {
19698            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19699        });
19700        cx.notify();
19701    }
19702
19703    pub fn text_highlights<'a, T: 'static>(
19704        &'a self,
19705        cx: &'a App,
19706    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19707        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19708    }
19709
19710    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19711        let cleared = self
19712            .display_map
19713            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19714        if cleared {
19715            cx.notify();
19716        }
19717    }
19718
19719    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19720        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19721            && self.focus_handle.is_focused(window)
19722    }
19723
19724    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19725        self.show_cursor_when_unfocused = is_enabled;
19726        cx.notify();
19727    }
19728
19729    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19730        cx.notify();
19731    }
19732
19733    fn on_debug_session_event(
19734        &mut self,
19735        _session: Entity<Session>,
19736        event: &SessionEvent,
19737        cx: &mut Context<Self>,
19738    ) {
19739        match event {
19740            SessionEvent::InvalidateInlineValue => {
19741                self.refresh_inline_values(cx);
19742            }
19743            _ => {}
19744        }
19745    }
19746
19747    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19748        let Some(project) = self.project.clone() else {
19749            return;
19750        };
19751
19752        if !self.inline_value_cache.enabled {
19753            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19754            self.splice_inlays(&inlays, Vec::new(), cx);
19755            return;
19756        }
19757
19758        let current_execution_position = self
19759            .highlighted_rows
19760            .get(&TypeId::of::<ActiveDebugLine>())
19761            .and_then(|lines| lines.last().map(|line| line.range.end));
19762
19763        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19764            let inline_values = editor
19765                .update(cx, |editor, cx| {
19766                    let Some(current_execution_position) = current_execution_position else {
19767                        return Some(Task::ready(Ok(Vec::new())));
19768                    };
19769
19770                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19771                        let snapshot = buffer.snapshot(cx);
19772
19773                        let excerpt = snapshot.excerpt_containing(
19774                            current_execution_position..current_execution_position,
19775                        )?;
19776
19777                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19778                    })?;
19779
19780                    let range =
19781                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19782
19783                    project.inline_values(buffer, range, cx)
19784                })
19785                .ok()
19786                .flatten()?
19787                .await
19788                .context("refreshing debugger inlays")
19789                .log_err()?;
19790
19791            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19792
19793            for (buffer_id, inline_value) in inline_values
19794                .into_iter()
19795                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19796            {
19797                buffer_inline_values
19798                    .entry(buffer_id)
19799                    .or_default()
19800                    .push(inline_value);
19801            }
19802
19803            editor
19804                .update(cx, |editor, cx| {
19805                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19806                    let mut new_inlays = Vec::default();
19807
19808                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19809                        let buffer_id = buffer_snapshot.remote_id();
19810                        buffer_inline_values
19811                            .get(&buffer_id)
19812                            .into_iter()
19813                            .flatten()
19814                            .for_each(|hint| {
19815                                let inlay = Inlay::debugger(
19816                                    post_inc(&mut editor.next_inlay_id),
19817                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19818                                    hint.text(),
19819                                );
19820                                if !inlay.text.chars().contains(&'\n') {
19821                                    new_inlays.push(inlay);
19822                                }
19823                            });
19824                    }
19825
19826                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19827                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19828
19829                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19830                })
19831                .ok()?;
19832            Some(())
19833        });
19834    }
19835
19836    fn on_buffer_event(
19837        &mut self,
19838        multibuffer: &Entity<MultiBuffer>,
19839        event: &multi_buffer::Event,
19840        window: &mut Window,
19841        cx: &mut Context<Self>,
19842    ) {
19843        match event {
19844            multi_buffer::Event::Edited {
19845                singleton_buffer_edited,
19846                edited_buffer,
19847            } => {
19848                self.scrollbar_marker_state.dirty = true;
19849                self.active_indent_guides_state.dirty = true;
19850                self.refresh_active_diagnostics(cx);
19851                self.refresh_code_actions(window, cx);
19852                self.refresh_selected_text_highlights(true, window, cx);
19853                self.refresh_single_line_folds(window, cx);
19854                refresh_matching_bracket_highlights(self, window, cx);
19855                if self.has_active_inline_completion() {
19856                    self.update_visible_inline_completion(window, cx);
19857                }
19858                if let Some(project) = self.project.as_ref() {
19859                    if let Some(edited_buffer) = edited_buffer {
19860                        project.update(cx, |project, cx| {
19861                            self.registered_buffers
19862                                .entry(edited_buffer.read(cx).remote_id())
19863                                .or_insert_with(|| {
19864                                    project
19865                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19866                                });
19867                        });
19868                    }
19869                }
19870                cx.emit(EditorEvent::BufferEdited);
19871                cx.emit(SearchEvent::MatchesInvalidated);
19872
19873                if let Some(buffer) = edited_buffer {
19874                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19875                }
19876
19877                if *singleton_buffer_edited {
19878                    if let Some(buffer) = edited_buffer {
19879                        if buffer.read(cx).file().is_none() {
19880                            cx.emit(EditorEvent::TitleChanged);
19881                        }
19882                    }
19883                    if let Some(project) = &self.project {
19884                        #[allow(clippy::mutable_key_type)]
19885                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19886                            multibuffer
19887                                .all_buffers()
19888                                .into_iter()
19889                                .filter_map(|buffer| {
19890                                    buffer.update(cx, |buffer, cx| {
19891                                        let language = buffer.language()?;
19892                                        let should_discard = project.update(cx, |project, cx| {
19893                                            project.is_local()
19894                                                && !project.has_language_servers_for(buffer, cx)
19895                                        });
19896                                        should_discard.not().then_some(language.clone())
19897                                    })
19898                                })
19899                                .collect::<HashSet<_>>()
19900                        });
19901                        if !languages_affected.is_empty() {
19902                            self.refresh_inlay_hints(
19903                                InlayHintRefreshReason::BufferEdited(languages_affected),
19904                                cx,
19905                            );
19906                        }
19907                    }
19908                }
19909
19910                let Some(project) = &self.project else { return };
19911                let (telemetry, is_via_ssh) = {
19912                    let project = project.read(cx);
19913                    let telemetry = project.client().telemetry().clone();
19914                    let is_via_ssh = project.is_via_ssh();
19915                    (telemetry, is_via_ssh)
19916                };
19917                refresh_linked_ranges(self, window, cx);
19918                telemetry.log_edit_event("editor", is_via_ssh);
19919            }
19920            multi_buffer::Event::ExcerptsAdded {
19921                buffer,
19922                predecessor,
19923                excerpts,
19924            } => {
19925                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19926                let buffer_id = buffer.read(cx).remote_id();
19927                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19928                    if let Some(project) = &self.project {
19929                        update_uncommitted_diff_for_buffer(
19930                            cx.entity(),
19931                            project,
19932                            [buffer.clone()],
19933                            self.buffer.clone(),
19934                            cx,
19935                        )
19936                        .detach();
19937                    }
19938                }
19939                self.update_lsp_data(false, Some(buffer_id), window, cx);
19940                cx.emit(EditorEvent::ExcerptsAdded {
19941                    buffer: buffer.clone(),
19942                    predecessor: *predecessor,
19943                    excerpts: excerpts.clone(),
19944                });
19945                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19946            }
19947            multi_buffer::Event::ExcerptsRemoved {
19948                ids,
19949                removed_buffer_ids,
19950            } => {
19951                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19952                let buffer = self.buffer.read(cx);
19953                self.registered_buffers
19954                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19955                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19956                cx.emit(EditorEvent::ExcerptsRemoved {
19957                    ids: ids.clone(),
19958                    removed_buffer_ids: removed_buffer_ids.clone(),
19959                });
19960            }
19961            multi_buffer::Event::ExcerptsEdited {
19962                excerpt_ids,
19963                buffer_ids,
19964            } => {
19965                self.display_map.update(cx, |map, cx| {
19966                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19967                });
19968                cx.emit(EditorEvent::ExcerptsEdited {
19969                    ids: excerpt_ids.clone(),
19970                });
19971            }
19972            multi_buffer::Event::ExcerptsExpanded { ids } => {
19973                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19974                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19975            }
19976            multi_buffer::Event::Reparsed(buffer_id) => {
19977                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19978                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19979
19980                cx.emit(EditorEvent::Reparsed(*buffer_id));
19981            }
19982            multi_buffer::Event::DiffHunksToggled => {
19983                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19984            }
19985            multi_buffer::Event::LanguageChanged(buffer_id) => {
19986                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19987                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19988                cx.emit(EditorEvent::Reparsed(*buffer_id));
19989                cx.notify();
19990            }
19991            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19992            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19993            multi_buffer::Event::FileHandleChanged
19994            | multi_buffer::Event::Reloaded
19995            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19996            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19997            multi_buffer::Event::DiagnosticsUpdated => {
19998                self.update_diagnostics_state(window, cx);
19999            }
20000            _ => {}
20001        };
20002    }
20003
20004    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20005        if !self.diagnostics_enabled() {
20006            return;
20007        }
20008        self.refresh_active_diagnostics(cx);
20009        self.refresh_inline_diagnostics(true, window, cx);
20010        self.scrollbar_marker_state.dirty = true;
20011        cx.notify();
20012    }
20013
20014    pub fn start_temporary_diff_override(&mut self) {
20015        self.load_diff_task.take();
20016        self.temporary_diff_override = true;
20017    }
20018
20019    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20020        self.temporary_diff_override = false;
20021        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20022        self.buffer.update(cx, |buffer, cx| {
20023            buffer.set_all_diff_hunks_collapsed(cx);
20024        });
20025
20026        if let Some(project) = self.project.clone() {
20027            self.load_diff_task = Some(
20028                update_uncommitted_diff_for_buffer(
20029                    cx.entity(),
20030                    &project,
20031                    self.buffer.read(cx).all_buffers(),
20032                    self.buffer.clone(),
20033                    cx,
20034                )
20035                .shared(),
20036            );
20037        }
20038    }
20039
20040    fn on_display_map_changed(
20041        &mut self,
20042        _: Entity<DisplayMap>,
20043        _: &mut Window,
20044        cx: &mut Context<Self>,
20045    ) {
20046        cx.notify();
20047    }
20048
20049    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20050        if self.diagnostics_enabled() {
20051            let new_severity = EditorSettings::get_global(cx)
20052                .diagnostics_max_severity
20053                .unwrap_or(DiagnosticSeverity::Hint);
20054            self.set_max_diagnostics_severity(new_severity, cx);
20055        }
20056        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20057        self.update_edit_prediction_settings(cx);
20058        self.refresh_inline_completion(true, false, window, cx);
20059        self.refresh_inline_values(cx);
20060        self.refresh_inlay_hints(
20061            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20062                self.selections.newest_anchor().head(),
20063                &self.buffer.read(cx).snapshot(cx),
20064                cx,
20065            )),
20066            cx,
20067        );
20068
20069        let old_cursor_shape = self.cursor_shape;
20070
20071        {
20072            let editor_settings = EditorSettings::get_global(cx);
20073            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20074            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20075            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20076            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20077        }
20078
20079        if old_cursor_shape != self.cursor_shape {
20080            cx.emit(EditorEvent::CursorShapeChanged);
20081        }
20082
20083        let project_settings = ProjectSettings::get_global(cx);
20084        self.serialize_dirty_buffers =
20085            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20086
20087        if self.mode.is_full() {
20088            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20089            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20090            if self.show_inline_diagnostics != show_inline_diagnostics {
20091                self.show_inline_diagnostics = show_inline_diagnostics;
20092                self.refresh_inline_diagnostics(false, window, cx);
20093            }
20094
20095            if self.git_blame_inline_enabled != inline_blame_enabled {
20096                self.toggle_git_blame_inline_internal(false, window, cx);
20097            }
20098
20099            let minimap_settings = EditorSettings::get_global(cx).minimap;
20100            if self.minimap_visibility != MinimapVisibility::Disabled {
20101                if self.minimap_visibility.settings_visibility()
20102                    != minimap_settings.minimap_enabled()
20103                {
20104                    self.set_minimap_visibility(
20105                        MinimapVisibility::for_mode(self.mode(), cx),
20106                        window,
20107                        cx,
20108                    );
20109                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20110                    minimap_entity.update(cx, |minimap_editor, cx| {
20111                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20112                    })
20113                }
20114            }
20115        }
20116
20117        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20118            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20119        }) {
20120            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20121                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20122            }
20123            self.refresh_colors(false, None, window, cx);
20124        }
20125
20126        cx.notify();
20127    }
20128
20129    pub fn set_searchable(&mut self, searchable: bool) {
20130        self.searchable = searchable;
20131    }
20132
20133    pub fn searchable(&self) -> bool {
20134        self.searchable
20135    }
20136
20137    fn open_proposed_changes_editor(
20138        &mut self,
20139        _: &OpenProposedChangesEditor,
20140        window: &mut Window,
20141        cx: &mut Context<Self>,
20142    ) {
20143        let Some(workspace) = self.workspace() else {
20144            cx.propagate();
20145            return;
20146        };
20147
20148        let selections = self.selections.all::<usize>(cx);
20149        let multi_buffer = self.buffer.read(cx);
20150        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20151        let mut new_selections_by_buffer = HashMap::default();
20152        for selection in selections {
20153            for (buffer, range, _) in
20154                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20155            {
20156                let mut range = range.to_point(buffer);
20157                range.start.column = 0;
20158                range.end.column = buffer.line_len(range.end.row);
20159                new_selections_by_buffer
20160                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20161                    .or_insert(Vec::new())
20162                    .push(range)
20163            }
20164        }
20165
20166        let proposed_changes_buffers = new_selections_by_buffer
20167            .into_iter()
20168            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20169            .collect::<Vec<_>>();
20170        let proposed_changes_editor = cx.new(|cx| {
20171            ProposedChangesEditor::new(
20172                "Proposed changes",
20173                proposed_changes_buffers,
20174                self.project.clone(),
20175                window,
20176                cx,
20177            )
20178        });
20179
20180        window.defer(cx, move |window, cx| {
20181            workspace.update(cx, |workspace, cx| {
20182                workspace.active_pane().update(cx, |pane, cx| {
20183                    pane.add_item(
20184                        Box::new(proposed_changes_editor),
20185                        true,
20186                        true,
20187                        None,
20188                        window,
20189                        cx,
20190                    );
20191                });
20192            });
20193        });
20194    }
20195
20196    pub fn open_excerpts_in_split(
20197        &mut self,
20198        _: &OpenExcerptsSplit,
20199        window: &mut Window,
20200        cx: &mut Context<Self>,
20201    ) {
20202        self.open_excerpts_common(None, true, window, cx)
20203    }
20204
20205    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20206        self.open_excerpts_common(None, false, window, cx)
20207    }
20208
20209    fn open_excerpts_common(
20210        &mut self,
20211        jump_data: Option<JumpData>,
20212        split: bool,
20213        window: &mut Window,
20214        cx: &mut Context<Self>,
20215    ) {
20216        let Some(workspace) = self.workspace() else {
20217            cx.propagate();
20218            return;
20219        };
20220
20221        if self.buffer.read(cx).is_singleton() {
20222            cx.propagate();
20223            return;
20224        }
20225
20226        let mut new_selections_by_buffer = HashMap::default();
20227        match &jump_data {
20228            Some(JumpData::MultiBufferPoint {
20229                excerpt_id,
20230                position,
20231                anchor,
20232                line_offset_from_top,
20233            }) => {
20234                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20235                if let Some(buffer) = multi_buffer_snapshot
20236                    .buffer_id_for_excerpt(*excerpt_id)
20237                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20238                {
20239                    let buffer_snapshot = buffer.read(cx).snapshot();
20240                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20241                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20242                    } else {
20243                        buffer_snapshot.clip_point(*position, Bias::Left)
20244                    };
20245                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20246                    new_selections_by_buffer.insert(
20247                        buffer,
20248                        (
20249                            vec![jump_to_offset..jump_to_offset],
20250                            Some(*line_offset_from_top),
20251                        ),
20252                    );
20253                }
20254            }
20255            Some(JumpData::MultiBufferRow {
20256                row,
20257                line_offset_from_top,
20258            }) => {
20259                let point = MultiBufferPoint::new(row.0, 0);
20260                if let Some((buffer, buffer_point, _)) =
20261                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20262                {
20263                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20264                    new_selections_by_buffer
20265                        .entry(buffer)
20266                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20267                        .0
20268                        .push(buffer_offset..buffer_offset)
20269                }
20270            }
20271            None => {
20272                let selections = self.selections.all::<usize>(cx);
20273                let multi_buffer = self.buffer.read(cx);
20274                for selection in selections {
20275                    for (snapshot, range, _, anchor) in multi_buffer
20276                        .snapshot(cx)
20277                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20278                    {
20279                        if let Some(anchor) = anchor {
20280                            // selection is in a deleted hunk
20281                            let Some(buffer_id) = anchor.buffer_id else {
20282                                continue;
20283                            };
20284                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20285                                continue;
20286                            };
20287                            let offset = text::ToOffset::to_offset(
20288                                &anchor.text_anchor,
20289                                &buffer_handle.read(cx).snapshot(),
20290                            );
20291                            let range = offset..offset;
20292                            new_selections_by_buffer
20293                                .entry(buffer_handle)
20294                                .or_insert((Vec::new(), None))
20295                                .0
20296                                .push(range)
20297                        } else {
20298                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20299                            else {
20300                                continue;
20301                            };
20302                            new_selections_by_buffer
20303                                .entry(buffer_handle)
20304                                .or_insert((Vec::new(), None))
20305                                .0
20306                                .push(range)
20307                        }
20308                    }
20309                }
20310            }
20311        }
20312
20313        new_selections_by_buffer
20314            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20315
20316        if new_selections_by_buffer.is_empty() {
20317            return;
20318        }
20319
20320        // We defer the pane interaction because we ourselves are a workspace item
20321        // and activating a new item causes the pane to call a method on us reentrantly,
20322        // which panics if we're on the stack.
20323        window.defer(cx, move |window, cx| {
20324            workspace.update(cx, |workspace, cx| {
20325                let pane = if split {
20326                    workspace.adjacent_pane(window, cx)
20327                } else {
20328                    workspace.active_pane().clone()
20329                };
20330
20331                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20332                    let editor = buffer
20333                        .read(cx)
20334                        .file()
20335                        .is_none()
20336                        .then(|| {
20337                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20338                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20339                            // Instead, we try to activate the existing editor in the pane first.
20340                            let (editor, pane_item_index) =
20341                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20342                                    let editor = item.downcast::<Editor>()?;
20343                                    let singleton_buffer =
20344                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20345                                    if singleton_buffer == buffer {
20346                                        Some((editor, i))
20347                                    } else {
20348                                        None
20349                                    }
20350                                })?;
20351                            pane.update(cx, |pane, cx| {
20352                                pane.activate_item(pane_item_index, true, true, window, cx)
20353                            });
20354                            Some(editor)
20355                        })
20356                        .flatten()
20357                        .unwrap_or_else(|| {
20358                            workspace.open_project_item::<Self>(
20359                                pane.clone(),
20360                                buffer,
20361                                true,
20362                                true,
20363                                window,
20364                                cx,
20365                            )
20366                        });
20367
20368                    editor.update(cx, |editor, cx| {
20369                        let autoscroll = match scroll_offset {
20370                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20371                            None => Autoscroll::newest(),
20372                        };
20373                        let nav_history = editor.nav_history.take();
20374                        editor.change_selections(
20375                            SelectionEffects::scroll(autoscroll),
20376                            window,
20377                            cx,
20378                            |s| {
20379                                s.select_ranges(ranges);
20380                            },
20381                        );
20382                        editor.nav_history = nav_history;
20383                    });
20384                }
20385            })
20386        });
20387    }
20388
20389    // For now, don't allow opening excerpts in buffers that aren't backed by
20390    // regular project files.
20391    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20392        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20393    }
20394
20395    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20396        let snapshot = self.buffer.read(cx).read(cx);
20397        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20398        Some(
20399            ranges
20400                .iter()
20401                .map(move |range| {
20402                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20403                })
20404                .collect(),
20405        )
20406    }
20407
20408    fn selection_replacement_ranges(
20409        &self,
20410        range: Range<OffsetUtf16>,
20411        cx: &mut App,
20412    ) -> Vec<Range<OffsetUtf16>> {
20413        let selections = self.selections.all::<OffsetUtf16>(cx);
20414        let newest_selection = selections
20415            .iter()
20416            .max_by_key(|selection| selection.id)
20417            .unwrap();
20418        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20419        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20420        let snapshot = self.buffer.read(cx).read(cx);
20421        selections
20422            .into_iter()
20423            .map(|mut selection| {
20424                selection.start.0 =
20425                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20426                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20427                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20428                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20429            })
20430            .collect()
20431    }
20432
20433    fn report_editor_event(
20434        &self,
20435        event_type: &'static str,
20436        file_extension: Option<String>,
20437        cx: &App,
20438    ) {
20439        if cfg!(any(test, feature = "test-support")) {
20440            return;
20441        }
20442
20443        let Some(project) = &self.project else { return };
20444
20445        // If None, we are in a file without an extension
20446        let file = self
20447            .buffer
20448            .read(cx)
20449            .as_singleton()
20450            .and_then(|b| b.read(cx).file());
20451        let file_extension = file_extension.or(file
20452            .as_ref()
20453            .and_then(|file| Path::new(file.file_name(cx)).extension())
20454            .and_then(|e| e.to_str())
20455            .map(|a| a.to_string()));
20456
20457        let vim_mode = vim_enabled(cx);
20458
20459        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20460        let copilot_enabled = edit_predictions_provider
20461            == language::language_settings::EditPredictionProvider::Copilot;
20462        let copilot_enabled_for_language = self
20463            .buffer
20464            .read(cx)
20465            .language_settings(cx)
20466            .show_edit_predictions;
20467
20468        let project = project.read(cx);
20469        telemetry::event!(
20470            event_type,
20471            file_extension,
20472            vim_mode,
20473            copilot_enabled,
20474            copilot_enabled_for_language,
20475            edit_predictions_provider,
20476            is_via_ssh = project.is_via_ssh(),
20477        );
20478    }
20479
20480    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20481    /// with each line being an array of {text, highlight} objects.
20482    fn copy_highlight_json(
20483        &mut self,
20484        _: &CopyHighlightJson,
20485        window: &mut Window,
20486        cx: &mut Context<Self>,
20487    ) {
20488        #[derive(Serialize)]
20489        struct Chunk<'a> {
20490            text: String,
20491            highlight: Option<&'a str>,
20492        }
20493
20494        let snapshot = self.buffer.read(cx).snapshot(cx);
20495        let range = self
20496            .selected_text_range(false, window, cx)
20497            .and_then(|selection| {
20498                if selection.range.is_empty() {
20499                    None
20500                } else {
20501                    Some(selection.range)
20502                }
20503            })
20504            .unwrap_or_else(|| 0..snapshot.len());
20505
20506        let chunks = snapshot.chunks(range, true);
20507        let mut lines = Vec::new();
20508        let mut line: VecDeque<Chunk> = VecDeque::new();
20509
20510        let Some(style) = self.style.as_ref() else {
20511            return;
20512        };
20513
20514        for chunk in chunks {
20515            let highlight = chunk
20516                .syntax_highlight_id
20517                .and_then(|id| id.name(&style.syntax));
20518            let mut chunk_lines = chunk.text.split('\n').peekable();
20519            while let Some(text) = chunk_lines.next() {
20520                let mut merged_with_last_token = false;
20521                if let Some(last_token) = line.back_mut() {
20522                    if last_token.highlight == highlight {
20523                        last_token.text.push_str(text);
20524                        merged_with_last_token = true;
20525                    }
20526                }
20527
20528                if !merged_with_last_token {
20529                    line.push_back(Chunk {
20530                        text: text.into(),
20531                        highlight,
20532                    });
20533                }
20534
20535                if chunk_lines.peek().is_some() {
20536                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20537                        line.pop_front();
20538                    }
20539                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20540                        line.pop_back();
20541                    }
20542
20543                    lines.push(mem::take(&mut line));
20544                }
20545            }
20546        }
20547
20548        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20549            return;
20550        };
20551        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20552    }
20553
20554    pub fn open_context_menu(
20555        &mut self,
20556        _: &OpenContextMenu,
20557        window: &mut Window,
20558        cx: &mut Context<Self>,
20559    ) {
20560        self.request_autoscroll(Autoscroll::newest(), cx);
20561        let position = self.selections.newest_display(cx).start;
20562        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20563    }
20564
20565    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20566        &self.inlay_hint_cache
20567    }
20568
20569    pub fn replay_insert_event(
20570        &mut self,
20571        text: &str,
20572        relative_utf16_range: Option<Range<isize>>,
20573        window: &mut Window,
20574        cx: &mut Context<Self>,
20575    ) {
20576        if !self.input_enabled {
20577            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20578            return;
20579        }
20580        if let Some(relative_utf16_range) = relative_utf16_range {
20581            let selections = self.selections.all::<OffsetUtf16>(cx);
20582            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20583                let new_ranges = selections.into_iter().map(|range| {
20584                    let start = OffsetUtf16(
20585                        range
20586                            .head()
20587                            .0
20588                            .saturating_add_signed(relative_utf16_range.start),
20589                    );
20590                    let end = OffsetUtf16(
20591                        range
20592                            .head()
20593                            .0
20594                            .saturating_add_signed(relative_utf16_range.end),
20595                    );
20596                    start..end
20597                });
20598                s.select_ranges(new_ranges);
20599            });
20600        }
20601
20602        self.handle_input(text, window, cx);
20603    }
20604
20605    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20606        let Some(provider) = self.semantics_provider.as_ref() else {
20607            return false;
20608        };
20609
20610        let mut supports = false;
20611        self.buffer().update(cx, |this, cx| {
20612            this.for_each_buffer(|buffer| {
20613                supports |= provider.supports_inlay_hints(buffer, cx);
20614            });
20615        });
20616
20617        supports
20618    }
20619
20620    pub fn is_focused(&self, window: &Window) -> bool {
20621        self.focus_handle.is_focused(window)
20622    }
20623
20624    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20625        cx.emit(EditorEvent::Focused);
20626
20627        if let Some(descendant) = self
20628            .last_focused_descendant
20629            .take()
20630            .and_then(|descendant| descendant.upgrade())
20631        {
20632            window.focus(&descendant);
20633        } else {
20634            if let Some(blame) = self.blame.as_ref() {
20635                blame.update(cx, GitBlame::focus)
20636            }
20637
20638            self.blink_manager.update(cx, BlinkManager::enable);
20639            self.show_cursor_names(window, cx);
20640            self.buffer.update(cx, |buffer, cx| {
20641                buffer.finalize_last_transaction(cx);
20642                if self.leader_id.is_none() {
20643                    buffer.set_active_selections(
20644                        &self.selections.disjoint_anchors(),
20645                        self.selections.line_mode,
20646                        self.cursor_shape,
20647                        cx,
20648                    );
20649                }
20650            });
20651        }
20652    }
20653
20654    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20655        cx.emit(EditorEvent::FocusedIn)
20656    }
20657
20658    fn handle_focus_out(
20659        &mut self,
20660        event: FocusOutEvent,
20661        _window: &mut Window,
20662        cx: &mut Context<Self>,
20663    ) {
20664        if event.blurred != self.focus_handle {
20665            self.last_focused_descendant = Some(event.blurred);
20666        }
20667        self.selection_drag_state = SelectionDragState::None;
20668        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20669    }
20670
20671    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20672        self.blink_manager.update(cx, BlinkManager::disable);
20673        self.buffer
20674            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20675
20676        if let Some(blame) = self.blame.as_ref() {
20677            blame.update(cx, GitBlame::blur)
20678        }
20679        if !self.hover_state.focused(window, cx) {
20680            hide_hover(self, cx);
20681        }
20682        if !self
20683            .context_menu
20684            .borrow()
20685            .as_ref()
20686            .is_some_and(|context_menu| context_menu.focused(window, cx))
20687        {
20688            self.hide_context_menu(window, cx);
20689        }
20690        self.discard_inline_completion(false, cx);
20691        cx.emit(EditorEvent::Blurred);
20692        cx.notify();
20693    }
20694
20695    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20696        let mut pending: String = window
20697            .pending_input_keystrokes()
20698            .into_iter()
20699            .flatten()
20700            .filter_map(|keystroke| {
20701                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20702                    keystroke.key_char.clone()
20703                } else {
20704                    None
20705                }
20706            })
20707            .collect();
20708
20709        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20710            pending = "".to_string();
20711        }
20712
20713        let existing_pending = self
20714            .text_highlights::<PendingInput>(cx)
20715            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20716        if existing_pending.is_none() && pending.is_empty() {
20717            return;
20718        }
20719        let transaction =
20720            self.transact(window, cx, |this, window, cx| {
20721                let selections = this.selections.all::<usize>(cx);
20722                let edits = selections
20723                    .iter()
20724                    .map(|selection| (selection.end..selection.end, pending.clone()));
20725                this.edit(edits, cx);
20726                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20727                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20728                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20729                    }));
20730                });
20731                if let Some(existing_ranges) = existing_pending {
20732                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20733                    this.edit(edits, cx);
20734                }
20735            });
20736
20737        let snapshot = self.snapshot(window, cx);
20738        let ranges = self
20739            .selections
20740            .all::<usize>(cx)
20741            .into_iter()
20742            .map(|selection| {
20743                snapshot.buffer_snapshot.anchor_after(selection.end)
20744                    ..snapshot
20745                        .buffer_snapshot
20746                        .anchor_before(selection.end + pending.len())
20747            })
20748            .collect();
20749
20750        if pending.is_empty() {
20751            self.clear_highlights::<PendingInput>(cx);
20752        } else {
20753            self.highlight_text::<PendingInput>(
20754                ranges,
20755                HighlightStyle {
20756                    underline: Some(UnderlineStyle {
20757                        thickness: px(1.),
20758                        color: None,
20759                        wavy: false,
20760                    }),
20761                    ..Default::default()
20762                },
20763                cx,
20764            );
20765        }
20766
20767        self.ime_transaction = self.ime_transaction.or(transaction);
20768        if let Some(transaction) = self.ime_transaction {
20769            self.buffer.update(cx, |buffer, cx| {
20770                buffer.group_until_transaction(transaction, cx);
20771            });
20772        }
20773
20774        if self.text_highlights::<PendingInput>(cx).is_none() {
20775            self.ime_transaction.take();
20776        }
20777    }
20778
20779    pub fn register_action_renderer(
20780        &mut self,
20781        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20782    ) -> Subscription {
20783        let id = self.next_editor_action_id.post_inc();
20784        self.editor_actions
20785            .borrow_mut()
20786            .insert(id, Box::new(listener));
20787
20788        let editor_actions = self.editor_actions.clone();
20789        Subscription::new(move || {
20790            editor_actions.borrow_mut().remove(&id);
20791        })
20792    }
20793
20794    pub fn register_action<A: Action>(
20795        &mut self,
20796        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20797    ) -> Subscription {
20798        let id = self.next_editor_action_id.post_inc();
20799        let listener = Arc::new(listener);
20800        self.editor_actions.borrow_mut().insert(
20801            id,
20802            Box::new(move |_, window, _| {
20803                let listener = listener.clone();
20804                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20805                    let action = action.downcast_ref().unwrap();
20806                    if phase == DispatchPhase::Bubble {
20807                        listener(action, window, cx)
20808                    }
20809                })
20810            }),
20811        );
20812
20813        let editor_actions = self.editor_actions.clone();
20814        Subscription::new(move || {
20815            editor_actions.borrow_mut().remove(&id);
20816        })
20817    }
20818
20819    pub fn file_header_size(&self) -> u32 {
20820        FILE_HEADER_HEIGHT
20821    }
20822
20823    pub fn restore(
20824        &mut self,
20825        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20826        window: &mut Window,
20827        cx: &mut Context<Self>,
20828    ) {
20829        let workspace = self.workspace();
20830        let project = self.project.as_ref();
20831        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20832            let mut tasks = Vec::new();
20833            for (buffer_id, changes) in revert_changes {
20834                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20835                    buffer.update(cx, |buffer, cx| {
20836                        buffer.edit(
20837                            changes
20838                                .into_iter()
20839                                .map(|(range, text)| (range, text.to_string())),
20840                            None,
20841                            cx,
20842                        );
20843                    });
20844
20845                    if let Some(project) =
20846                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20847                    {
20848                        project.update(cx, |project, cx| {
20849                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20850                        })
20851                    }
20852                }
20853            }
20854            tasks
20855        });
20856        cx.spawn_in(window, async move |_, cx| {
20857            for (buffer, task) in save_tasks {
20858                let result = task.await;
20859                if result.is_err() {
20860                    let Some(path) = buffer
20861                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20862                        .ok()
20863                    else {
20864                        continue;
20865                    };
20866                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20867                        let Some(task) = cx
20868                            .update_window_entity(&workspace, |workspace, window, cx| {
20869                                workspace
20870                                    .open_path_preview(path, None, false, false, false, window, cx)
20871                            })
20872                            .ok()
20873                        else {
20874                            continue;
20875                        };
20876                        task.await.log_err();
20877                    }
20878                }
20879            }
20880        })
20881        .detach();
20882        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20883            selections.refresh()
20884        });
20885    }
20886
20887    pub fn to_pixel_point(
20888        &self,
20889        source: multi_buffer::Anchor,
20890        editor_snapshot: &EditorSnapshot,
20891        window: &mut Window,
20892    ) -> Option<gpui::Point<Pixels>> {
20893        let source_point = source.to_display_point(editor_snapshot);
20894        self.display_to_pixel_point(source_point, editor_snapshot, window)
20895    }
20896
20897    pub fn display_to_pixel_point(
20898        &self,
20899        source: DisplayPoint,
20900        editor_snapshot: &EditorSnapshot,
20901        window: &mut Window,
20902    ) -> Option<gpui::Point<Pixels>> {
20903        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20904        let text_layout_details = self.text_layout_details(window);
20905        let scroll_top = text_layout_details
20906            .scroll_anchor
20907            .scroll_position(editor_snapshot)
20908            .y;
20909
20910        if source.row().as_f32() < scroll_top.floor() {
20911            return None;
20912        }
20913        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20914        let source_y = line_height * (source.row().as_f32() - scroll_top);
20915        Some(gpui::Point::new(source_x, source_y))
20916    }
20917
20918    pub fn has_visible_completions_menu(&self) -> bool {
20919        !self.edit_prediction_preview_is_active()
20920            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20921                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20922            })
20923    }
20924
20925    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20926        if self.mode.is_minimap() {
20927            return;
20928        }
20929        self.addons
20930            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20931    }
20932
20933    pub fn unregister_addon<T: Addon>(&mut self) {
20934        self.addons.remove(&std::any::TypeId::of::<T>());
20935    }
20936
20937    pub fn addon<T: Addon>(&self) -> Option<&T> {
20938        let type_id = std::any::TypeId::of::<T>();
20939        self.addons
20940            .get(&type_id)
20941            .and_then(|item| item.to_any().downcast_ref::<T>())
20942    }
20943
20944    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20945        let type_id = std::any::TypeId::of::<T>();
20946        self.addons
20947            .get_mut(&type_id)
20948            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20949    }
20950
20951    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20952        let text_layout_details = self.text_layout_details(window);
20953        let style = &text_layout_details.editor_style;
20954        let font_id = window.text_system().resolve_font(&style.text.font());
20955        let font_size = style.text.font_size.to_pixels(window.rem_size());
20956        let line_height = style.text.line_height_in_pixels(window.rem_size());
20957        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20958        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20959
20960        CharacterDimensions {
20961            em_width,
20962            em_advance,
20963            line_height,
20964        }
20965    }
20966
20967    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20968        self.load_diff_task.clone()
20969    }
20970
20971    fn read_metadata_from_db(
20972        &mut self,
20973        item_id: u64,
20974        workspace_id: WorkspaceId,
20975        window: &mut Window,
20976        cx: &mut Context<Editor>,
20977    ) {
20978        if self.is_singleton(cx)
20979            && !self.mode.is_minimap()
20980            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20981        {
20982            let buffer_snapshot = OnceCell::new();
20983
20984            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20985                if !folds.is_empty() {
20986                    let snapshot =
20987                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20988                    self.fold_ranges(
20989                        folds
20990                            .into_iter()
20991                            .map(|(start, end)| {
20992                                snapshot.clip_offset(start, Bias::Left)
20993                                    ..snapshot.clip_offset(end, Bias::Right)
20994                            })
20995                            .collect(),
20996                        false,
20997                        window,
20998                        cx,
20999                    );
21000                }
21001            }
21002
21003            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21004                if !selections.is_empty() {
21005                    let snapshot =
21006                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21007                    // skip adding the initial selection to selection history
21008                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21009                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21010                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21011                            snapshot.clip_offset(start, Bias::Left)
21012                                ..snapshot.clip_offset(end, Bias::Right)
21013                        }));
21014                    });
21015                    self.selection_history.mode = SelectionHistoryMode::Normal;
21016                }
21017            };
21018        }
21019
21020        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21021    }
21022
21023    fn update_lsp_data(
21024        &mut self,
21025        ignore_cache: bool,
21026        for_buffer: Option<BufferId>,
21027        window: &mut Window,
21028        cx: &mut Context<'_, Self>,
21029    ) {
21030        self.pull_diagnostics(for_buffer, window, cx);
21031        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21032    }
21033}
21034
21035fn vim_enabled(cx: &App) -> bool {
21036    cx.global::<SettingsStore>()
21037        .raw_user_settings()
21038        .get("vim_mode")
21039        == Some(&serde_json::Value::Bool(true))
21040}
21041
21042fn process_completion_for_edit(
21043    completion: &Completion,
21044    intent: CompletionIntent,
21045    buffer: &Entity<Buffer>,
21046    cursor_position: &text::Anchor,
21047    cx: &mut Context<Editor>,
21048) -> CompletionEdit {
21049    let buffer = buffer.read(cx);
21050    let buffer_snapshot = buffer.snapshot();
21051    let (snippet, new_text) = if completion.is_snippet() {
21052        // Workaround for typescript language server issues so that methods don't expand within
21053        // strings and functions with type expressions. The previous point is used because the query
21054        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21055        let mut snippet_source = completion.new_text.clone();
21056        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21057        previous_point.column = previous_point.column.saturating_sub(1);
21058        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21059            if scope.prefers_label_for_snippet_in_completion() {
21060                if let Some(label) = completion.label() {
21061                    if matches!(
21062                        completion.kind(),
21063                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21064                    ) {
21065                        snippet_source = label;
21066                    }
21067                }
21068            }
21069        }
21070        match Snippet::parse(&snippet_source).log_err() {
21071            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21072            None => (None, completion.new_text.clone()),
21073        }
21074    } else {
21075        (None, completion.new_text.clone())
21076    };
21077
21078    let mut range_to_replace = {
21079        let replace_range = &completion.replace_range;
21080        if let CompletionSource::Lsp {
21081            insert_range: Some(insert_range),
21082            ..
21083        } = &completion.source
21084        {
21085            debug_assert_eq!(
21086                insert_range.start, replace_range.start,
21087                "insert_range and replace_range should start at the same position"
21088            );
21089            debug_assert!(
21090                insert_range
21091                    .start
21092                    .cmp(&cursor_position, &buffer_snapshot)
21093                    .is_le(),
21094                "insert_range should start before or at cursor position"
21095            );
21096            debug_assert!(
21097                replace_range
21098                    .start
21099                    .cmp(&cursor_position, &buffer_snapshot)
21100                    .is_le(),
21101                "replace_range should start before or at cursor position"
21102            );
21103            debug_assert!(
21104                insert_range
21105                    .end
21106                    .cmp(&cursor_position, &buffer_snapshot)
21107                    .is_le(),
21108                "insert_range should end before or at cursor position"
21109            );
21110
21111            let should_replace = match intent {
21112                CompletionIntent::CompleteWithInsert => false,
21113                CompletionIntent::CompleteWithReplace => true,
21114                CompletionIntent::Complete | CompletionIntent::Compose => {
21115                    let insert_mode =
21116                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21117                            .completions
21118                            .lsp_insert_mode;
21119                    match insert_mode {
21120                        LspInsertMode::Insert => false,
21121                        LspInsertMode::Replace => true,
21122                        LspInsertMode::ReplaceSubsequence => {
21123                            let mut text_to_replace = buffer.chars_for_range(
21124                                buffer.anchor_before(replace_range.start)
21125                                    ..buffer.anchor_after(replace_range.end),
21126                            );
21127                            let mut current_needle = text_to_replace.next();
21128                            for haystack_ch in completion.label.text.chars() {
21129                                if let Some(needle_ch) = current_needle {
21130                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21131                                        current_needle = text_to_replace.next();
21132                                    }
21133                                }
21134                            }
21135                            current_needle.is_none()
21136                        }
21137                        LspInsertMode::ReplaceSuffix => {
21138                            if replace_range
21139                                .end
21140                                .cmp(&cursor_position, &buffer_snapshot)
21141                                .is_gt()
21142                            {
21143                                let range_after_cursor = *cursor_position..replace_range.end;
21144                                let text_after_cursor = buffer
21145                                    .text_for_range(
21146                                        buffer.anchor_before(range_after_cursor.start)
21147                                            ..buffer.anchor_after(range_after_cursor.end),
21148                                    )
21149                                    .collect::<String>()
21150                                    .to_ascii_lowercase();
21151                                completion
21152                                    .label
21153                                    .text
21154                                    .to_ascii_lowercase()
21155                                    .ends_with(&text_after_cursor)
21156                            } else {
21157                                true
21158                            }
21159                        }
21160                    }
21161                }
21162            };
21163
21164            if should_replace {
21165                replace_range.clone()
21166            } else {
21167                insert_range.clone()
21168            }
21169        } else {
21170            replace_range.clone()
21171        }
21172    };
21173
21174    if range_to_replace
21175        .end
21176        .cmp(&cursor_position, &buffer_snapshot)
21177        .is_lt()
21178    {
21179        range_to_replace.end = *cursor_position;
21180    }
21181
21182    CompletionEdit {
21183        new_text,
21184        replace_range: range_to_replace.to_offset(&buffer),
21185        snippet,
21186    }
21187}
21188
21189struct CompletionEdit {
21190    new_text: String,
21191    replace_range: Range<usize>,
21192    snippet: Option<Snippet>,
21193}
21194
21195fn insert_extra_newline_brackets(
21196    buffer: &MultiBufferSnapshot,
21197    range: Range<usize>,
21198    language: &language::LanguageScope,
21199) -> bool {
21200    let leading_whitespace_len = buffer
21201        .reversed_chars_at(range.start)
21202        .take_while(|c| c.is_whitespace() && *c != '\n')
21203        .map(|c| c.len_utf8())
21204        .sum::<usize>();
21205    let trailing_whitespace_len = buffer
21206        .chars_at(range.end)
21207        .take_while(|c| c.is_whitespace() && *c != '\n')
21208        .map(|c| c.len_utf8())
21209        .sum::<usize>();
21210    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21211
21212    language.brackets().any(|(pair, enabled)| {
21213        let pair_start = pair.start.trim_end();
21214        let pair_end = pair.end.trim_start();
21215
21216        enabled
21217            && pair.newline
21218            && buffer.contains_str_at(range.end, pair_end)
21219            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21220    })
21221}
21222
21223fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21224    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21225        [(buffer, range, _)] => (*buffer, range.clone()),
21226        _ => return false,
21227    };
21228    let pair = {
21229        let mut result: Option<BracketMatch> = None;
21230
21231        for pair in buffer
21232            .all_bracket_ranges(range.clone())
21233            .filter(move |pair| {
21234                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21235            })
21236        {
21237            let len = pair.close_range.end - pair.open_range.start;
21238
21239            if let Some(existing) = &result {
21240                let existing_len = existing.close_range.end - existing.open_range.start;
21241                if len > existing_len {
21242                    continue;
21243                }
21244            }
21245
21246            result = Some(pair);
21247        }
21248
21249        result
21250    };
21251    let Some(pair) = pair else {
21252        return false;
21253    };
21254    pair.newline_only
21255        && buffer
21256            .chars_for_range(pair.open_range.end..range.start)
21257            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21258            .all(|c| c.is_whitespace() && c != '\n')
21259}
21260
21261fn update_uncommitted_diff_for_buffer(
21262    editor: Entity<Editor>,
21263    project: &Entity<Project>,
21264    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21265    buffer: Entity<MultiBuffer>,
21266    cx: &mut App,
21267) -> Task<()> {
21268    let mut tasks = Vec::new();
21269    project.update(cx, |project, cx| {
21270        for buffer in buffers {
21271            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21272                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21273            }
21274        }
21275    });
21276    cx.spawn(async move |cx| {
21277        let diffs = future::join_all(tasks).await;
21278        if editor
21279            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21280            .unwrap_or(false)
21281        {
21282            return;
21283        }
21284
21285        buffer
21286            .update(cx, |buffer, cx| {
21287                for diff in diffs.into_iter().flatten() {
21288                    buffer.add_diff(diff, cx);
21289                }
21290            })
21291            .ok();
21292    })
21293}
21294
21295fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21296    let tab_size = tab_size.get() as usize;
21297    let mut width = offset;
21298
21299    for ch in text.chars() {
21300        width += if ch == '\t' {
21301            tab_size - (width % tab_size)
21302        } else {
21303            1
21304        };
21305    }
21306
21307    width - offset
21308}
21309
21310#[cfg(test)]
21311mod tests {
21312    use super::*;
21313
21314    #[test]
21315    fn test_string_size_with_expanded_tabs() {
21316        let nz = |val| NonZeroU32::new(val).unwrap();
21317        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21318        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21319        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21320        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21321        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21322        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21323        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21324        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21325    }
21326}
21327
21328/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21329struct WordBreakingTokenizer<'a> {
21330    input: &'a str,
21331}
21332
21333impl<'a> WordBreakingTokenizer<'a> {
21334    fn new(input: &'a str) -> Self {
21335        Self { input }
21336    }
21337}
21338
21339fn is_char_ideographic(ch: char) -> bool {
21340    use unicode_script::Script::*;
21341    use unicode_script::UnicodeScript;
21342    matches!(ch.script(), Han | Tangut | Yi)
21343}
21344
21345fn is_grapheme_ideographic(text: &str) -> bool {
21346    text.chars().any(is_char_ideographic)
21347}
21348
21349fn is_grapheme_whitespace(text: &str) -> bool {
21350    text.chars().any(|x| x.is_whitespace())
21351}
21352
21353fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21354    text.chars().next().map_or(false, |ch| {
21355        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21356    })
21357}
21358
21359#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21360enum WordBreakToken<'a> {
21361    Word { token: &'a str, grapheme_len: usize },
21362    InlineWhitespace { token: &'a str, grapheme_len: usize },
21363    Newline,
21364}
21365
21366impl<'a> Iterator for WordBreakingTokenizer<'a> {
21367    /// Yields a span, the count of graphemes in the token, and whether it was
21368    /// whitespace. Note that it also breaks at word boundaries.
21369    type Item = WordBreakToken<'a>;
21370
21371    fn next(&mut self) -> Option<Self::Item> {
21372        use unicode_segmentation::UnicodeSegmentation;
21373        if self.input.is_empty() {
21374            return None;
21375        }
21376
21377        let mut iter = self.input.graphemes(true).peekable();
21378        let mut offset = 0;
21379        let mut grapheme_len = 0;
21380        if let Some(first_grapheme) = iter.next() {
21381            let is_newline = first_grapheme == "\n";
21382            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21383            offset += first_grapheme.len();
21384            grapheme_len += 1;
21385            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21386                if let Some(grapheme) = iter.peek().copied() {
21387                    if should_stay_with_preceding_ideograph(grapheme) {
21388                        offset += grapheme.len();
21389                        grapheme_len += 1;
21390                    }
21391                }
21392            } else {
21393                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21394                let mut next_word_bound = words.peek().copied();
21395                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21396                    next_word_bound = words.next();
21397                }
21398                while let Some(grapheme) = iter.peek().copied() {
21399                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21400                        break;
21401                    };
21402                    if is_grapheme_whitespace(grapheme) != is_whitespace
21403                        || (grapheme == "\n") != is_newline
21404                    {
21405                        break;
21406                    };
21407                    offset += grapheme.len();
21408                    grapheme_len += 1;
21409                    iter.next();
21410                }
21411            }
21412            let token = &self.input[..offset];
21413            self.input = &self.input[offset..];
21414            if token == "\n" {
21415                Some(WordBreakToken::Newline)
21416            } else if is_whitespace {
21417                Some(WordBreakToken::InlineWhitespace {
21418                    token,
21419                    grapheme_len,
21420                })
21421            } else {
21422                Some(WordBreakToken::Word {
21423                    token,
21424                    grapheme_len,
21425                })
21426            }
21427        } else {
21428            None
21429        }
21430    }
21431}
21432
21433#[test]
21434fn test_word_breaking_tokenizer() {
21435    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21436        ("", &[]),
21437        ("  ", &[whitespace("  ", 2)]),
21438        ("Ʒ", &[word("Ʒ", 1)]),
21439        ("Ǽ", &[word("Ǽ", 1)]),
21440        ("", &[word("", 1)]),
21441        ("⋑⋑", &[word("⋑⋑", 2)]),
21442        (
21443            "原理,进而",
21444            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21445        ),
21446        (
21447            "hello world",
21448            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21449        ),
21450        (
21451            "hello, world",
21452            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21453        ),
21454        (
21455            "  hello world",
21456            &[
21457                whitespace("  ", 2),
21458                word("hello", 5),
21459                whitespace(" ", 1),
21460                word("world", 5),
21461            ],
21462        ),
21463        (
21464            "这是什么 \n 钢笔",
21465            &[
21466                word("", 1),
21467                word("", 1),
21468                word("", 1),
21469                word("", 1),
21470                whitespace(" ", 1),
21471                newline(),
21472                whitespace(" ", 1),
21473                word("", 1),
21474                word("", 1),
21475            ],
21476        ),
21477        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21478    ];
21479
21480    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21481        WordBreakToken::Word {
21482            token,
21483            grapheme_len,
21484        }
21485    }
21486
21487    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21488        WordBreakToken::InlineWhitespace {
21489            token,
21490            grapheme_len,
21491        }
21492    }
21493
21494    fn newline() -> WordBreakToken<'static> {
21495        WordBreakToken::Newline
21496    }
21497
21498    for (input, result) in tests {
21499        assert_eq!(
21500            WordBreakingTokenizer::new(input)
21501                .collect::<Vec<_>>()
21502                .as_slice(),
21503            *result,
21504        );
21505    }
21506}
21507
21508fn wrap_with_prefix(
21509    first_line_prefix: String,
21510    subsequent_lines_prefix: String,
21511    unwrapped_text: String,
21512    wrap_column: usize,
21513    tab_size: NonZeroU32,
21514    preserve_existing_whitespace: bool,
21515) -> String {
21516    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21517    let subsequent_lines_prefix_len =
21518        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21519    let mut wrapped_text = String::new();
21520    let mut current_line = first_line_prefix.clone();
21521    let mut is_first_line = true;
21522
21523    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21524    let mut current_line_len = first_line_prefix_len;
21525    let mut in_whitespace = false;
21526    for token in tokenizer {
21527        let have_preceding_whitespace = in_whitespace;
21528        match token {
21529            WordBreakToken::Word {
21530                token,
21531                grapheme_len,
21532            } => {
21533                in_whitespace = false;
21534                let current_prefix_len = if is_first_line {
21535                    first_line_prefix_len
21536                } else {
21537                    subsequent_lines_prefix_len
21538                };
21539                if current_line_len + grapheme_len > wrap_column
21540                    && current_line_len != current_prefix_len
21541                {
21542                    wrapped_text.push_str(current_line.trim_end());
21543                    wrapped_text.push('\n');
21544                    is_first_line = false;
21545                    current_line = subsequent_lines_prefix.clone();
21546                    current_line_len = subsequent_lines_prefix_len;
21547                }
21548                current_line.push_str(token);
21549                current_line_len += grapheme_len;
21550            }
21551            WordBreakToken::InlineWhitespace {
21552                mut token,
21553                mut grapheme_len,
21554            } => {
21555                in_whitespace = true;
21556                if have_preceding_whitespace && !preserve_existing_whitespace {
21557                    continue;
21558                }
21559                if !preserve_existing_whitespace {
21560                    token = " ";
21561                    grapheme_len = 1;
21562                }
21563                let current_prefix_len = if is_first_line {
21564                    first_line_prefix_len
21565                } else {
21566                    subsequent_lines_prefix_len
21567                };
21568                if current_line_len + grapheme_len > wrap_column {
21569                    wrapped_text.push_str(current_line.trim_end());
21570                    wrapped_text.push('\n');
21571                    is_first_line = false;
21572                    current_line = subsequent_lines_prefix.clone();
21573                    current_line_len = subsequent_lines_prefix_len;
21574                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21575                    current_line.push_str(token);
21576                    current_line_len += grapheme_len;
21577                }
21578            }
21579            WordBreakToken::Newline => {
21580                in_whitespace = true;
21581                let current_prefix_len = if is_first_line {
21582                    first_line_prefix_len
21583                } else {
21584                    subsequent_lines_prefix_len
21585                };
21586                if preserve_existing_whitespace {
21587                    wrapped_text.push_str(current_line.trim_end());
21588                    wrapped_text.push('\n');
21589                    is_first_line = false;
21590                    current_line = subsequent_lines_prefix.clone();
21591                    current_line_len = subsequent_lines_prefix_len;
21592                } else if have_preceding_whitespace {
21593                    continue;
21594                } else if current_line_len + 1 > wrap_column
21595                    && current_line_len != current_prefix_len
21596                {
21597                    wrapped_text.push_str(current_line.trim_end());
21598                    wrapped_text.push('\n');
21599                    is_first_line = false;
21600                    current_line = subsequent_lines_prefix.clone();
21601                    current_line_len = subsequent_lines_prefix_len;
21602                } else if current_line_len != current_prefix_len {
21603                    current_line.push(' ');
21604                    current_line_len += 1;
21605                }
21606            }
21607        }
21608    }
21609
21610    if !current_line.is_empty() {
21611        wrapped_text.push_str(&current_line);
21612    }
21613    wrapped_text
21614}
21615
21616#[test]
21617fn test_wrap_with_prefix() {
21618    assert_eq!(
21619        wrap_with_prefix(
21620            "# ".to_string(),
21621            "# ".to_string(),
21622            "abcdefg".to_string(),
21623            4,
21624            NonZeroU32::new(4).unwrap(),
21625            false,
21626        ),
21627        "# abcdefg"
21628    );
21629    assert_eq!(
21630        wrap_with_prefix(
21631            "".to_string(),
21632            "".to_string(),
21633            "\thello world".to_string(),
21634            8,
21635            NonZeroU32::new(4).unwrap(),
21636            false,
21637        ),
21638        "hello\nworld"
21639    );
21640    assert_eq!(
21641        wrap_with_prefix(
21642            "// ".to_string(),
21643            "// ".to_string(),
21644            "xx \nyy zz aa bb cc".to_string(),
21645            12,
21646            NonZeroU32::new(4).unwrap(),
21647            false,
21648        ),
21649        "// xx yy zz\n// aa bb cc"
21650    );
21651    assert_eq!(
21652        wrap_with_prefix(
21653            String::new(),
21654            String::new(),
21655            "这是什么 \n 钢笔".to_string(),
21656            3,
21657            NonZeroU32::new(4).unwrap(),
21658            false,
21659        ),
21660        "这是什\n么 钢\n"
21661    );
21662}
21663
21664pub trait CollaborationHub {
21665    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21666    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21667    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21668}
21669
21670impl CollaborationHub for Entity<Project> {
21671    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21672        self.read(cx).collaborators()
21673    }
21674
21675    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21676        self.read(cx).user_store().read(cx).participant_indices()
21677    }
21678
21679    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21680        let this = self.read(cx);
21681        let user_ids = this.collaborators().values().map(|c| c.user_id);
21682        this.user_store().read(cx).participant_names(user_ids, cx)
21683    }
21684}
21685
21686pub trait SemanticsProvider {
21687    fn hover(
21688        &self,
21689        buffer: &Entity<Buffer>,
21690        position: text::Anchor,
21691        cx: &mut App,
21692    ) -> Option<Task<Vec<project::Hover>>>;
21693
21694    fn inline_values(
21695        &self,
21696        buffer_handle: Entity<Buffer>,
21697        range: Range<text::Anchor>,
21698        cx: &mut App,
21699    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21700
21701    fn inlay_hints(
21702        &self,
21703        buffer_handle: Entity<Buffer>,
21704        range: Range<text::Anchor>,
21705        cx: &mut App,
21706    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21707
21708    fn resolve_inlay_hint(
21709        &self,
21710        hint: InlayHint,
21711        buffer_handle: Entity<Buffer>,
21712        server_id: LanguageServerId,
21713        cx: &mut App,
21714    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21715
21716    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21717
21718    fn document_highlights(
21719        &self,
21720        buffer: &Entity<Buffer>,
21721        position: text::Anchor,
21722        cx: &mut App,
21723    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21724
21725    fn definitions(
21726        &self,
21727        buffer: &Entity<Buffer>,
21728        position: text::Anchor,
21729        kind: GotoDefinitionKind,
21730        cx: &mut App,
21731    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21732
21733    fn range_for_rename(
21734        &self,
21735        buffer: &Entity<Buffer>,
21736        position: text::Anchor,
21737        cx: &mut App,
21738    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21739
21740    fn perform_rename(
21741        &self,
21742        buffer: &Entity<Buffer>,
21743        position: text::Anchor,
21744        new_name: String,
21745        cx: &mut App,
21746    ) -> Option<Task<Result<ProjectTransaction>>>;
21747}
21748
21749pub trait CompletionProvider {
21750    fn completions(
21751        &self,
21752        excerpt_id: ExcerptId,
21753        buffer: &Entity<Buffer>,
21754        buffer_position: text::Anchor,
21755        trigger: CompletionContext,
21756        window: &mut Window,
21757        cx: &mut Context<Editor>,
21758    ) -> Task<Result<Vec<CompletionResponse>>>;
21759
21760    fn resolve_completions(
21761        &self,
21762        _buffer: Entity<Buffer>,
21763        _completion_indices: Vec<usize>,
21764        _completions: Rc<RefCell<Box<[Completion]>>>,
21765        _cx: &mut Context<Editor>,
21766    ) -> Task<Result<bool>> {
21767        Task::ready(Ok(false))
21768    }
21769
21770    fn apply_additional_edits_for_completion(
21771        &self,
21772        _buffer: Entity<Buffer>,
21773        _completions: Rc<RefCell<Box<[Completion]>>>,
21774        _completion_index: usize,
21775        _push_to_history: bool,
21776        _cx: &mut Context<Editor>,
21777    ) -> Task<Result<Option<language::Transaction>>> {
21778        Task::ready(Ok(None))
21779    }
21780
21781    fn is_completion_trigger(
21782        &self,
21783        buffer: &Entity<Buffer>,
21784        position: language::Anchor,
21785        text: &str,
21786        trigger_in_words: bool,
21787        menu_is_open: bool,
21788        cx: &mut Context<Editor>,
21789    ) -> bool;
21790
21791    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21792
21793    fn sort_completions(&self) -> bool {
21794        true
21795    }
21796
21797    fn filter_completions(&self) -> bool {
21798        true
21799    }
21800}
21801
21802pub trait CodeActionProvider {
21803    fn id(&self) -> Arc<str>;
21804
21805    fn code_actions(
21806        &self,
21807        buffer: &Entity<Buffer>,
21808        range: Range<text::Anchor>,
21809        window: &mut Window,
21810        cx: &mut App,
21811    ) -> Task<Result<Vec<CodeAction>>>;
21812
21813    fn apply_code_action(
21814        &self,
21815        buffer_handle: Entity<Buffer>,
21816        action: CodeAction,
21817        excerpt_id: ExcerptId,
21818        push_to_history: bool,
21819        window: &mut Window,
21820        cx: &mut App,
21821    ) -> Task<Result<ProjectTransaction>>;
21822}
21823
21824impl CodeActionProvider for Entity<Project> {
21825    fn id(&self) -> Arc<str> {
21826        "project".into()
21827    }
21828
21829    fn code_actions(
21830        &self,
21831        buffer: &Entity<Buffer>,
21832        range: Range<text::Anchor>,
21833        _window: &mut Window,
21834        cx: &mut App,
21835    ) -> Task<Result<Vec<CodeAction>>> {
21836        self.update(cx, |project, cx| {
21837            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21838            let code_actions = project.code_actions(buffer, range, None, cx);
21839            cx.background_spawn(async move {
21840                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21841                Ok(code_lens_actions
21842                    .context("code lens fetch")?
21843                    .into_iter()
21844                    .chain(code_actions.context("code action fetch")?)
21845                    .collect())
21846            })
21847        })
21848    }
21849
21850    fn apply_code_action(
21851        &self,
21852        buffer_handle: Entity<Buffer>,
21853        action: CodeAction,
21854        _excerpt_id: ExcerptId,
21855        push_to_history: bool,
21856        _window: &mut Window,
21857        cx: &mut App,
21858    ) -> Task<Result<ProjectTransaction>> {
21859        self.update(cx, |project, cx| {
21860            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21861        })
21862    }
21863}
21864
21865fn snippet_completions(
21866    project: &Project,
21867    buffer: &Entity<Buffer>,
21868    buffer_position: text::Anchor,
21869    cx: &mut App,
21870) -> Task<Result<CompletionResponse>> {
21871    let languages = buffer.read(cx).languages_at(buffer_position);
21872    let snippet_store = project.snippets().read(cx);
21873
21874    let scopes: Vec<_> = languages
21875        .iter()
21876        .filter_map(|language| {
21877            let language_name = language.lsp_id();
21878            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21879
21880            if snippets.is_empty() {
21881                None
21882            } else {
21883                Some((language.default_scope(), snippets))
21884            }
21885        })
21886        .collect();
21887
21888    if scopes.is_empty() {
21889        return Task::ready(Ok(CompletionResponse {
21890            completions: vec![],
21891            is_incomplete: false,
21892        }));
21893    }
21894
21895    let snapshot = buffer.read(cx).text_snapshot();
21896    let chars: String = snapshot
21897        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21898        .collect();
21899    let executor = cx.background_executor().clone();
21900
21901    cx.background_spawn(async move {
21902        let mut is_incomplete = false;
21903        let mut completions: Vec<Completion> = Vec::new();
21904        for (scope, snippets) in scopes.into_iter() {
21905            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21906            let mut last_word = chars
21907                .chars()
21908                .take_while(|c| classifier.is_word(*c))
21909                .collect::<String>();
21910            last_word = last_word.chars().rev().collect();
21911
21912            if last_word.is_empty() {
21913                return Ok(CompletionResponse {
21914                    completions: vec![],
21915                    is_incomplete: true,
21916                });
21917            }
21918
21919            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21920            let to_lsp = |point: &text::Anchor| {
21921                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21922                point_to_lsp(end)
21923            };
21924            let lsp_end = to_lsp(&buffer_position);
21925
21926            let candidates = snippets
21927                .iter()
21928                .enumerate()
21929                .flat_map(|(ix, snippet)| {
21930                    snippet
21931                        .prefix
21932                        .iter()
21933                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21934                })
21935                .collect::<Vec<StringMatchCandidate>>();
21936
21937            const MAX_RESULTS: usize = 100;
21938            let mut matches = fuzzy::match_strings(
21939                &candidates,
21940                &last_word,
21941                last_word.chars().any(|c| c.is_uppercase()),
21942                true,
21943                MAX_RESULTS,
21944                &Default::default(),
21945                executor.clone(),
21946            )
21947            .await;
21948
21949            if matches.len() >= MAX_RESULTS {
21950                is_incomplete = true;
21951            }
21952
21953            // Remove all candidates where the query's start does not match the start of any word in the candidate
21954            if let Some(query_start) = last_word.chars().next() {
21955                matches.retain(|string_match| {
21956                    split_words(&string_match.string).any(|word| {
21957                        // Check that the first codepoint of the word as lowercase matches the first
21958                        // codepoint of the query as lowercase
21959                        word.chars()
21960                            .flat_map(|codepoint| codepoint.to_lowercase())
21961                            .zip(query_start.to_lowercase())
21962                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21963                    })
21964                });
21965            }
21966
21967            let matched_strings = matches
21968                .into_iter()
21969                .map(|m| m.string)
21970                .collect::<HashSet<_>>();
21971
21972            completions.extend(snippets.iter().filter_map(|snippet| {
21973                let matching_prefix = snippet
21974                    .prefix
21975                    .iter()
21976                    .find(|prefix| matched_strings.contains(*prefix))?;
21977                let start = as_offset - last_word.len();
21978                let start = snapshot.anchor_before(start);
21979                let range = start..buffer_position;
21980                let lsp_start = to_lsp(&start);
21981                let lsp_range = lsp::Range {
21982                    start: lsp_start,
21983                    end: lsp_end,
21984                };
21985                Some(Completion {
21986                    replace_range: range,
21987                    new_text: snippet.body.clone(),
21988                    source: CompletionSource::Lsp {
21989                        insert_range: None,
21990                        server_id: LanguageServerId(usize::MAX),
21991                        resolved: true,
21992                        lsp_completion: Box::new(lsp::CompletionItem {
21993                            label: snippet.prefix.first().unwrap().clone(),
21994                            kind: Some(CompletionItemKind::SNIPPET),
21995                            label_details: snippet.description.as_ref().map(|description| {
21996                                lsp::CompletionItemLabelDetails {
21997                                    detail: Some(description.clone()),
21998                                    description: None,
21999                                }
22000                            }),
22001                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22002                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22003                                lsp::InsertReplaceEdit {
22004                                    new_text: snippet.body.clone(),
22005                                    insert: lsp_range,
22006                                    replace: lsp_range,
22007                                },
22008                            )),
22009                            filter_text: Some(snippet.body.clone()),
22010                            sort_text: Some(char::MAX.to_string()),
22011                            ..lsp::CompletionItem::default()
22012                        }),
22013                        lsp_defaults: None,
22014                    },
22015                    label: CodeLabel {
22016                        text: matching_prefix.clone(),
22017                        runs: Vec::new(),
22018                        filter_range: 0..matching_prefix.len(),
22019                    },
22020                    icon_path: None,
22021                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22022                        single_line: snippet.name.clone().into(),
22023                        plain_text: snippet
22024                            .description
22025                            .clone()
22026                            .map(|description| description.into()),
22027                    }),
22028                    insert_text_mode: None,
22029                    confirm: None,
22030                })
22031            }))
22032        }
22033
22034        Ok(CompletionResponse {
22035            completions,
22036            is_incomplete,
22037        })
22038    })
22039}
22040
22041impl CompletionProvider for Entity<Project> {
22042    fn completions(
22043        &self,
22044        _excerpt_id: ExcerptId,
22045        buffer: &Entity<Buffer>,
22046        buffer_position: text::Anchor,
22047        options: CompletionContext,
22048        _window: &mut Window,
22049        cx: &mut Context<Editor>,
22050    ) -> Task<Result<Vec<CompletionResponse>>> {
22051        self.update(cx, |project, cx| {
22052            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22053            let project_completions = project.completions(buffer, buffer_position, options, cx);
22054            cx.background_spawn(async move {
22055                let mut responses = project_completions.await?;
22056                let snippets = snippets.await?;
22057                if !snippets.completions.is_empty() {
22058                    responses.push(snippets);
22059                }
22060                Ok(responses)
22061            })
22062        })
22063    }
22064
22065    fn resolve_completions(
22066        &self,
22067        buffer: Entity<Buffer>,
22068        completion_indices: Vec<usize>,
22069        completions: Rc<RefCell<Box<[Completion]>>>,
22070        cx: &mut Context<Editor>,
22071    ) -> Task<Result<bool>> {
22072        self.update(cx, |project, cx| {
22073            project.lsp_store().update(cx, |lsp_store, cx| {
22074                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22075            })
22076        })
22077    }
22078
22079    fn apply_additional_edits_for_completion(
22080        &self,
22081        buffer: Entity<Buffer>,
22082        completions: Rc<RefCell<Box<[Completion]>>>,
22083        completion_index: usize,
22084        push_to_history: bool,
22085        cx: &mut Context<Editor>,
22086    ) -> Task<Result<Option<language::Transaction>>> {
22087        self.update(cx, |project, cx| {
22088            project.lsp_store().update(cx, |lsp_store, cx| {
22089                lsp_store.apply_additional_edits_for_completion(
22090                    buffer,
22091                    completions,
22092                    completion_index,
22093                    push_to_history,
22094                    cx,
22095                )
22096            })
22097        })
22098    }
22099
22100    fn is_completion_trigger(
22101        &self,
22102        buffer: &Entity<Buffer>,
22103        position: language::Anchor,
22104        text: &str,
22105        trigger_in_words: bool,
22106        menu_is_open: bool,
22107        cx: &mut Context<Editor>,
22108    ) -> bool {
22109        let mut chars = text.chars();
22110        let char = if let Some(char) = chars.next() {
22111            char
22112        } else {
22113            return false;
22114        };
22115        if chars.next().is_some() {
22116            return false;
22117        }
22118
22119        let buffer = buffer.read(cx);
22120        let snapshot = buffer.snapshot();
22121        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22122            return false;
22123        }
22124        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22125        if trigger_in_words && classifier.is_word(char) {
22126            return true;
22127        }
22128
22129        buffer.completion_triggers().contains(text)
22130    }
22131}
22132
22133impl SemanticsProvider for Entity<Project> {
22134    fn hover(
22135        &self,
22136        buffer: &Entity<Buffer>,
22137        position: text::Anchor,
22138        cx: &mut App,
22139    ) -> Option<Task<Vec<project::Hover>>> {
22140        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22141    }
22142
22143    fn document_highlights(
22144        &self,
22145        buffer: &Entity<Buffer>,
22146        position: text::Anchor,
22147        cx: &mut App,
22148    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22149        Some(self.update(cx, |project, cx| {
22150            project.document_highlights(buffer, position, cx)
22151        }))
22152    }
22153
22154    fn definitions(
22155        &self,
22156        buffer: &Entity<Buffer>,
22157        position: text::Anchor,
22158        kind: GotoDefinitionKind,
22159        cx: &mut App,
22160    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22161        Some(self.update(cx, |project, cx| match kind {
22162            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22163            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22164            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22165            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22166        }))
22167    }
22168
22169    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22170        // TODO: make this work for remote projects
22171        self.update(cx, |project, cx| {
22172            if project
22173                .active_debug_session(cx)
22174                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22175            {
22176                return true;
22177            }
22178
22179            buffer.update(cx, |buffer, cx| {
22180                project.any_language_server_supports_inlay_hints(buffer, cx)
22181            })
22182        })
22183    }
22184
22185    fn inline_values(
22186        &self,
22187        buffer_handle: Entity<Buffer>,
22188        range: Range<text::Anchor>,
22189        cx: &mut App,
22190    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22191        self.update(cx, |project, cx| {
22192            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22193
22194            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22195        })
22196    }
22197
22198    fn inlay_hints(
22199        &self,
22200        buffer_handle: Entity<Buffer>,
22201        range: Range<text::Anchor>,
22202        cx: &mut App,
22203    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22204        Some(self.update(cx, |project, cx| {
22205            project.inlay_hints(buffer_handle, range, cx)
22206        }))
22207    }
22208
22209    fn resolve_inlay_hint(
22210        &self,
22211        hint: InlayHint,
22212        buffer_handle: Entity<Buffer>,
22213        server_id: LanguageServerId,
22214        cx: &mut App,
22215    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22216        Some(self.update(cx, |project, cx| {
22217            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22218        }))
22219    }
22220
22221    fn range_for_rename(
22222        &self,
22223        buffer: &Entity<Buffer>,
22224        position: text::Anchor,
22225        cx: &mut App,
22226    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22227        Some(self.update(cx, |project, cx| {
22228            let buffer = buffer.clone();
22229            let task = project.prepare_rename(buffer.clone(), position, cx);
22230            cx.spawn(async move |_, cx| {
22231                Ok(match task.await? {
22232                    PrepareRenameResponse::Success(range) => Some(range),
22233                    PrepareRenameResponse::InvalidPosition => None,
22234                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22235                        // Fallback on using TreeSitter info to determine identifier range
22236                        buffer.read_with(cx, |buffer, _| {
22237                            let snapshot = buffer.snapshot();
22238                            let (range, kind) = snapshot.surrounding_word(position, false);
22239                            if kind != Some(CharKind::Word) {
22240                                return None;
22241                            }
22242                            Some(
22243                                snapshot.anchor_before(range.start)
22244                                    ..snapshot.anchor_after(range.end),
22245                            )
22246                        })?
22247                    }
22248                })
22249            })
22250        }))
22251    }
22252
22253    fn perform_rename(
22254        &self,
22255        buffer: &Entity<Buffer>,
22256        position: text::Anchor,
22257        new_name: String,
22258        cx: &mut App,
22259    ) -> Option<Task<Result<ProjectTransaction>>> {
22260        Some(self.update(cx, |project, cx| {
22261            project.perform_rename(buffer.clone(), position, new_name, cx)
22262        }))
22263    }
22264}
22265
22266fn inlay_hint_settings(
22267    location: Anchor,
22268    snapshot: &MultiBufferSnapshot,
22269    cx: &mut Context<Editor>,
22270) -> InlayHintSettings {
22271    let file = snapshot.file_at(location);
22272    let language = snapshot.language_at(location).map(|l| l.name());
22273    language_settings(language, file, cx).inlay_hints
22274}
22275
22276fn consume_contiguous_rows(
22277    contiguous_row_selections: &mut Vec<Selection<Point>>,
22278    selection: &Selection<Point>,
22279    display_map: &DisplaySnapshot,
22280    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22281) -> (MultiBufferRow, MultiBufferRow) {
22282    contiguous_row_selections.push(selection.clone());
22283    let start_row = starting_row(selection, display_map);
22284    let mut end_row = ending_row(selection, display_map);
22285
22286    while let Some(next_selection) = selections.peek() {
22287        if next_selection.start.row <= end_row.0 {
22288            end_row = ending_row(next_selection, display_map);
22289            contiguous_row_selections.push(selections.next().unwrap().clone());
22290        } else {
22291            break;
22292        }
22293    }
22294    (start_row, end_row)
22295}
22296
22297fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22298    if selection.start.column > 0 {
22299        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22300    } else {
22301        MultiBufferRow(selection.start.row)
22302    }
22303}
22304
22305fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22306    if next_selection.end.column > 0 || next_selection.is_empty() {
22307        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22308    } else {
22309        MultiBufferRow(next_selection.end.row)
22310    }
22311}
22312
22313impl EditorSnapshot {
22314    pub fn remote_selections_in_range<'a>(
22315        &'a self,
22316        range: &'a Range<Anchor>,
22317        collaboration_hub: &dyn CollaborationHub,
22318        cx: &'a App,
22319    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22320        let participant_names = collaboration_hub.user_names(cx);
22321        let participant_indices = collaboration_hub.user_participant_indices(cx);
22322        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22323        let collaborators_by_replica_id = collaborators_by_peer_id
22324            .values()
22325            .map(|collaborator| (collaborator.replica_id, collaborator))
22326            .collect::<HashMap<_, _>>();
22327        self.buffer_snapshot
22328            .selections_in_range(range, false)
22329            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22330                if replica_id == AGENT_REPLICA_ID {
22331                    Some(RemoteSelection {
22332                        replica_id,
22333                        selection,
22334                        cursor_shape,
22335                        line_mode,
22336                        collaborator_id: CollaboratorId::Agent,
22337                        user_name: Some("Agent".into()),
22338                        color: cx.theme().players().agent(),
22339                    })
22340                } else {
22341                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22342                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22343                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22344                    Some(RemoteSelection {
22345                        replica_id,
22346                        selection,
22347                        cursor_shape,
22348                        line_mode,
22349                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22350                        user_name,
22351                        color: if let Some(index) = participant_index {
22352                            cx.theme().players().color_for_participant(index.0)
22353                        } else {
22354                            cx.theme().players().absent()
22355                        },
22356                    })
22357                }
22358            })
22359    }
22360
22361    pub fn hunks_for_ranges(
22362        &self,
22363        ranges: impl IntoIterator<Item = Range<Point>>,
22364    ) -> Vec<MultiBufferDiffHunk> {
22365        let mut hunks = Vec::new();
22366        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22367            HashMap::default();
22368        for query_range in ranges {
22369            let query_rows =
22370                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22371            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22372                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22373            ) {
22374                // Include deleted hunks that are adjacent to the query range, because
22375                // otherwise they would be missed.
22376                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22377                if hunk.status().is_deleted() {
22378                    intersects_range |= hunk.row_range.start == query_rows.end;
22379                    intersects_range |= hunk.row_range.end == query_rows.start;
22380                }
22381                if intersects_range {
22382                    if !processed_buffer_rows
22383                        .entry(hunk.buffer_id)
22384                        .or_default()
22385                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22386                    {
22387                        continue;
22388                    }
22389                    hunks.push(hunk);
22390                }
22391            }
22392        }
22393
22394        hunks
22395    }
22396
22397    fn display_diff_hunks_for_rows<'a>(
22398        &'a self,
22399        display_rows: Range<DisplayRow>,
22400        folded_buffers: &'a HashSet<BufferId>,
22401    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22402        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22403        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22404
22405        self.buffer_snapshot
22406            .diff_hunks_in_range(buffer_start..buffer_end)
22407            .filter_map(|hunk| {
22408                if folded_buffers.contains(&hunk.buffer_id) {
22409                    return None;
22410                }
22411
22412                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22413                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22414
22415                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22416                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22417
22418                let display_hunk = if hunk_display_start.column() != 0 {
22419                    DisplayDiffHunk::Folded {
22420                        display_row: hunk_display_start.row(),
22421                    }
22422                } else {
22423                    let mut end_row = hunk_display_end.row();
22424                    if hunk_display_end.column() > 0 {
22425                        end_row.0 += 1;
22426                    }
22427                    let is_created_file = hunk.is_created_file();
22428                    DisplayDiffHunk::Unfolded {
22429                        status: hunk.status(),
22430                        diff_base_byte_range: hunk.diff_base_byte_range,
22431                        display_row_range: hunk_display_start.row()..end_row,
22432                        multi_buffer_range: Anchor::range_in_buffer(
22433                            hunk.excerpt_id,
22434                            hunk.buffer_id,
22435                            hunk.buffer_range,
22436                        ),
22437                        is_created_file,
22438                    }
22439                };
22440
22441                Some(display_hunk)
22442            })
22443    }
22444
22445    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22446        self.display_snapshot.buffer_snapshot.language_at(position)
22447    }
22448
22449    pub fn is_focused(&self) -> bool {
22450        self.is_focused
22451    }
22452
22453    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22454        self.placeholder_text.as_ref()
22455    }
22456
22457    pub fn scroll_position(&self) -> gpui::Point<f32> {
22458        self.scroll_anchor.scroll_position(&self.display_snapshot)
22459    }
22460
22461    fn gutter_dimensions(
22462        &self,
22463        font_id: FontId,
22464        font_size: Pixels,
22465        max_line_number_width: Pixels,
22466        cx: &App,
22467    ) -> Option<GutterDimensions> {
22468        if !self.show_gutter {
22469            return None;
22470        }
22471
22472        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22473        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22474
22475        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22476            matches!(
22477                ProjectSettings::get_global(cx).git.git_gutter,
22478                Some(GitGutterSetting::TrackedFiles)
22479            )
22480        });
22481        let gutter_settings = EditorSettings::get_global(cx).gutter;
22482        let show_line_numbers = self
22483            .show_line_numbers
22484            .unwrap_or(gutter_settings.line_numbers);
22485        let line_gutter_width = if show_line_numbers {
22486            // Avoid flicker-like gutter resizes when the line number gains another digit by
22487            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22488            let min_width_for_number_on_gutter =
22489                ch_advance * gutter_settings.min_line_number_digits as f32;
22490            max_line_number_width.max(min_width_for_number_on_gutter)
22491        } else {
22492            0.0.into()
22493        };
22494
22495        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22496        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22497
22498        let git_blame_entries_width =
22499            self.git_blame_gutter_max_author_length
22500                .map(|max_author_length| {
22501                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22502                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22503
22504                    /// The number of characters to dedicate to gaps and margins.
22505                    const SPACING_WIDTH: usize = 4;
22506
22507                    let max_char_count = max_author_length.min(renderer.max_author_length())
22508                        + ::git::SHORT_SHA_LENGTH
22509                        + MAX_RELATIVE_TIMESTAMP.len()
22510                        + SPACING_WIDTH;
22511
22512                    ch_advance * max_char_count
22513                });
22514
22515        let is_singleton = self.buffer_snapshot.is_singleton();
22516
22517        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22518        left_padding += if !is_singleton {
22519            ch_width * 4.0
22520        } else if show_runnables || show_breakpoints {
22521            ch_width * 3.0
22522        } else if show_git_gutter && show_line_numbers {
22523            ch_width * 2.0
22524        } else if show_git_gutter || show_line_numbers {
22525            ch_width
22526        } else {
22527            px(0.)
22528        };
22529
22530        let shows_folds = is_singleton && gutter_settings.folds;
22531
22532        let right_padding = if shows_folds && show_line_numbers {
22533            ch_width * 4.0
22534        } else if shows_folds || (!is_singleton && show_line_numbers) {
22535            ch_width * 3.0
22536        } else if show_line_numbers {
22537            ch_width
22538        } else {
22539            px(0.)
22540        };
22541
22542        Some(GutterDimensions {
22543            left_padding,
22544            right_padding,
22545            width: line_gutter_width + left_padding + right_padding,
22546            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22547            git_blame_entries_width,
22548        })
22549    }
22550
22551    pub fn render_crease_toggle(
22552        &self,
22553        buffer_row: MultiBufferRow,
22554        row_contains_cursor: bool,
22555        editor: Entity<Editor>,
22556        window: &mut Window,
22557        cx: &mut App,
22558    ) -> Option<AnyElement> {
22559        let folded = self.is_line_folded(buffer_row);
22560        let mut is_foldable = false;
22561
22562        if let Some(crease) = self
22563            .crease_snapshot
22564            .query_row(buffer_row, &self.buffer_snapshot)
22565        {
22566            is_foldable = true;
22567            match crease {
22568                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22569                    if let Some(render_toggle) = render_toggle {
22570                        let toggle_callback =
22571                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22572                                if folded {
22573                                    editor.update(cx, |editor, cx| {
22574                                        editor.fold_at(buffer_row, window, cx)
22575                                    });
22576                                } else {
22577                                    editor.update(cx, |editor, cx| {
22578                                        editor.unfold_at(buffer_row, window, cx)
22579                                    });
22580                                }
22581                            });
22582                        return Some((render_toggle)(
22583                            buffer_row,
22584                            folded,
22585                            toggle_callback,
22586                            window,
22587                            cx,
22588                        ));
22589                    }
22590                }
22591            }
22592        }
22593
22594        is_foldable |= self.starts_indent(buffer_row);
22595
22596        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22597            Some(
22598                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22599                    .toggle_state(folded)
22600                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22601                        if folded {
22602                            this.unfold_at(buffer_row, window, cx);
22603                        } else {
22604                            this.fold_at(buffer_row, window, cx);
22605                        }
22606                    }))
22607                    .into_any_element(),
22608            )
22609        } else {
22610            None
22611        }
22612    }
22613
22614    pub fn render_crease_trailer(
22615        &self,
22616        buffer_row: MultiBufferRow,
22617        window: &mut Window,
22618        cx: &mut App,
22619    ) -> Option<AnyElement> {
22620        let folded = self.is_line_folded(buffer_row);
22621        if let Crease::Inline { render_trailer, .. } = self
22622            .crease_snapshot
22623            .query_row(buffer_row, &self.buffer_snapshot)?
22624        {
22625            let render_trailer = render_trailer.as_ref()?;
22626            Some(render_trailer(buffer_row, folded, window, cx))
22627        } else {
22628            None
22629        }
22630    }
22631}
22632
22633impl Deref for EditorSnapshot {
22634    type Target = DisplaySnapshot;
22635
22636    fn deref(&self) -> &Self::Target {
22637        &self.display_snapshot
22638    }
22639}
22640
22641#[derive(Clone, Debug, PartialEq, Eq)]
22642pub enum EditorEvent {
22643    InputIgnored {
22644        text: Arc<str>,
22645    },
22646    InputHandled {
22647        utf16_range_to_replace: Option<Range<isize>>,
22648        text: Arc<str>,
22649    },
22650    ExcerptsAdded {
22651        buffer: Entity<Buffer>,
22652        predecessor: ExcerptId,
22653        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22654    },
22655    ExcerptsRemoved {
22656        ids: Vec<ExcerptId>,
22657        removed_buffer_ids: Vec<BufferId>,
22658    },
22659    BufferFoldToggled {
22660        ids: Vec<ExcerptId>,
22661        folded: bool,
22662    },
22663    ExcerptsEdited {
22664        ids: Vec<ExcerptId>,
22665    },
22666    ExcerptsExpanded {
22667        ids: Vec<ExcerptId>,
22668    },
22669    BufferEdited,
22670    Edited {
22671        transaction_id: clock::Lamport,
22672    },
22673    Reparsed(BufferId),
22674    Focused,
22675    FocusedIn,
22676    Blurred,
22677    DirtyChanged,
22678    Saved,
22679    TitleChanged,
22680    DiffBaseChanged,
22681    SelectionsChanged {
22682        local: bool,
22683    },
22684    ScrollPositionChanged {
22685        local: bool,
22686        autoscroll: bool,
22687    },
22688    Closed,
22689    TransactionUndone {
22690        transaction_id: clock::Lamport,
22691    },
22692    TransactionBegun {
22693        transaction_id: clock::Lamport,
22694    },
22695    Reloaded,
22696    CursorShapeChanged,
22697    PushedToNavHistory {
22698        anchor: Anchor,
22699        is_deactivate: bool,
22700    },
22701}
22702
22703impl EventEmitter<EditorEvent> for Editor {}
22704
22705impl Focusable for Editor {
22706    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22707        self.focus_handle.clone()
22708    }
22709}
22710
22711impl Render for Editor {
22712    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22713        let settings = ThemeSettings::get_global(cx);
22714
22715        let mut text_style = match self.mode {
22716            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22717                color: cx.theme().colors().editor_foreground,
22718                font_family: settings.ui_font.family.clone(),
22719                font_features: settings.ui_font.features.clone(),
22720                font_fallbacks: settings.ui_font.fallbacks.clone(),
22721                font_size: rems(0.875).into(),
22722                font_weight: settings.ui_font.weight,
22723                line_height: relative(settings.buffer_line_height.value()),
22724                ..Default::default()
22725            },
22726            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22727                color: cx.theme().colors().editor_foreground,
22728                font_family: settings.buffer_font.family.clone(),
22729                font_features: settings.buffer_font.features.clone(),
22730                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22731                font_size: settings.buffer_font_size(cx).into(),
22732                font_weight: settings.buffer_font.weight,
22733                line_height: relative(settings.buffer_line_height.value()),
22734                ..Default::default()
22735            },
22736        };
22737        if let Some(text_style_refinement) = &self.text_style_refinement {
22738            text_style.refine(text_style_refinement)
22739        }
22740
22741        let background = match self.mode {
22742            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22743            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22744            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22745            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22746        };
22747
22748        EditorElement::new(
22749            &cx.entity(),
22750            EditorStyle {
22751                background,
22752                border: cx.theme().colors().border,
22753                local_player: cx.theme().players().local(),
22754                text: text_style,
22755                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22756                syntax: cx.theme().syntax().clone(),
22757                status: cx.theme().status().clone(),
22758                inlay_hints_style: make_inlay_hints_style(cx),
22759                inline_completion_styles: make_suggestion_styles(cx),
22760                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22761                show_underlines: self.diagnostics_enabled(),
22762            },
22763        )
22764    }
22765}
22766
22767impl EntityInputHandler for Editor {
22768    fn text_for_range(
22769        &mut self,
22770        range_utf16: Range<usize>,
22771        adjusted_range: &mut Option<Range<usize>>,
22772        _: &mut Window,
22773        cx: &mut Context<Self>,
22774    ) -> Option<String> {
22775        let snapshot = self.buffer.read(cx).read(cx);
22776        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22777        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22778        if (start.0..end.0) != range_utf16 {
22779            adjusted_range.replace(start.0..end.0);
22780        }
22781        Some(snapshot.text_for_range(start..end).collect())
22782    }
22783
22784    fn selected_text_range(
22785        &mut self,
22786        ignore_disabled_input: bool,
22787        _: &mut Window,
22788        cx: &mut Context<Self>,
22789    ) -> Option<UTF16Selection> {
22790        // Prevent the IME menu from appearing when holding down an alphabetic key
22791        // while input is disabled.
22792        if !ignore_disabled_input && !self.input_enabled {
22793            return None;
22794        }
22795
22796        let selection = self.selections.newest::<OffsetUtf16>(cx);
22797        let range = selection.range();
22798
22799        Some(UTF16Selection {
22800            range: range.start.0..range.end.0,
22801            reversed: selection.reversed,
22802        })
22803    }
22804
22805    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22806        let snapshot = self.buffer.read(cx).read(cx);
22807        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22808        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22809    }
22810
22811    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22812        self.clear_highlights::<InputComposition>(cx);
22813        self.ime_transaction.take();
22814    }
22815
22816    fn replace_text_in_range(
22817        &mut self,
22818        range_utf16: Option<Range<usize>>,
22819        text: &str,
22820        window: &mut Window,
22821        cx: &mut Context<Self>,
22822    ) {
22823        if !self.input_enabled {
22824            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22825            return;
22826        }
22827
22828        self.transact(window, cx, |this, window, cx| {
22829            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22830                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22831                Some(this.selection_replacement_ranges(range_utf16, cx))
22832            } else {
22833                this.marked_text_ranges(cx)
22834            };
22835
22836            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22837                let newest_selection_id = this.selections.newest_anchor().id;
22838                this.selections
22839                    .all::<OffsetUtf16>(cx)
22840                    .iter()
22841                    .zip(ranges_to_replace.iter())
22842                    .find_map(|(selection, range)| {
22843                        if selection.id == newest_selection_id {
22844                            Some(
22845                                (range.start.0 as isize - selection.head().0 as isize)
22846                                    ..(range.end.0 as isize - selection.head().0 as isize),
22847                            )
22848                        } else {
22849                            None
22850                        }
22851                    })
22852            });
22853
22854            cx.emit(EditorEvent::InputHandled {
22855                utf16_range_to_replace: range_to_replace,
22856                text: text.into(),
22857            });
22858
22859            if let Some(new_selected_ranges) = new_selected_ranges {
22860                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22861                    selections.select_ranges(new_selected_ranges)
22862                });
22863                this.backspace(&Default::default(), window, cx);
22864            }
22865
22866            this.handle_input(text, window, cx);
22867        });
22868
22869        if let Some(transaction) = self.ime_transaction {
22870            self.buffer.update(cx, |buffer, cx| {
22871                buffer.group_until_transaction(transaction, cx);
22872            });
22873        }
22874
22875        self.unmark_text(window, cx);
22876    }
22877
22878    fn replace_and_mark_text_in_range(
22879        &mut self,
22880        range_utf16: Option<Range<usize>>,
22881        text: &str,
22882        new_selected_range_utf16: Option<Range<usize>>,
22883        window: &mut Window,
22884        cx: &mut Context<Self>,
22885    ) {
22886        if !self.input_enabled {
22887            return;
22888        }
22889
22890        let transaction = self.transact(window, cx, |this, window, cx| {
22891            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22892                let snapshot = this.buffer.read(cx).read(cx);
22893                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22894                    for marked_range in &mut marked_ranges {
22895                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22896                        marked_range.start.0 += relative_range_utf16.start;
22897                        marked_range.start =
22898                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22899                        marked_range.end =
22900                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22901                    }
22902                }
22903                Some(marked_ranges)
22904            } else if let Some(range_utf16) = range_utf16 {
22905                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22906                Some(this.selection_replacement_ranges(range_utf16, cx))
22907            } else {
22908                None
22909            };
22910
22911            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22912                let newest_selection_id = this.selections.newest_anchor().id;
22913                this.selections
22914                    .all::<OffsetUtf16>(cx)
22915                    .iter()
22916                    .zip(ranges_to_replace.iter())
22917                    .find_map(|(selection, range)| {
22918                        if selection.id == newest_selection_id {
22919                            Some(
22920                                (range.start.0 as isize - selection.head().0 as isize)
22921                                    ..(range.end.0 as isize - selection.head().0 as isize),
22922                            )
22923                        } else {
22924                            None
22925                        }
22926                    })
22927            });
22928
22929            cx.emit(EditorEvent::InputHandled {
22930                utf16_range_to_replace: range_to_replace,
22931                text: text.into(),
22932            });
22933
22934            if let Some(ranges) = ranges_to_replace {
22935                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22936                    s.select_ranges(ranges)
22937                });
22938            }
22939
22940            let marked_ranges = {
22941                let snapshot = this.buffer.read(cx).read(cx);
22942                this.selections
22943                    .disjoint_anchors()
22944                    .iter()
22945                    .map(|selection| {
22946                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22947                    })
22948                    .collect::<Vec<_>>()
22949            };
22950
22951            if text.is_empty() {
22952                this.unmark_text(window, cx);
22953            } else {
22954                this.highlight_text::<InputComposition>(
22955                    marked_ranges.clone(),
22956                    HighlightStyle {
22957                        underline: Some(UnderlineStyle {
22958                            thickness: px(1.),
22959                            color: None,
22960                            wavy: false,
22961                        }),
22962                        ..Default::default()
22963                    },
22964                    cx,
22965                );
22966            }
22967
22968            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22969            let use_autoclose = this.use_autoclose;
22970            let use_auto_surround = this.use_auto_surround;
22971            this.set_use_autoclose(false);
22972            this.set_use_auto_surround(false);
22973            this.handle_input(text, window, cx);
22974            this.set_use_autoclose(use_autoclose);
22975            this.set_use_auto_surround(use_auto_surround);
22976
22977            if let Some(new_selected_range) = new_selected_range_utf16 {
22978                let snapshot = this.buffer.read(cx).read(cx);
22979                let new_selected_ranges = marked_ranges
22980                    .into_iter()
22981                    .map(|marked_range| {
22982                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22983                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22984                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22985                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22986                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22987                    })
22988                    .collect::<Vec<_>>();
22989
22990                drop(snapshot);
22991                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22992                    selections.select_ranges(new_selected_ranges)
22993                });
22994            }
22995        });
22996
22997        self.ime_transaction = self.ime_transaction.or(transaction);
22998        if let Some(transaction) = self.ime_transaction {
22999            self.buffer.update(cx, |buffer, cx| {
23000                buffer.group_until_transaction(transaction, cx);
23001            });
23002        }
23003
23004        if self.text_highlights::<InputComposition>(cx).is_none() {
23005            self.ime_transaction.take();
23006        }
23007    }
23008
23009    fn bounds_for_range(
23010        &mut self,
23011        range_utf16: Range<usize>,
23012        element_bounds: gpui::Bounds<Pixels>,
23013        window: &mut Window,
23014        cx: &mut Context<Self>,
23015    ) -> Option<gpui::Bounds<Pixels>> {
23016        let text_layout_details = self.text_layout_details(window);
23017        let CharacterDimensions {
23018            em_width,
23019            em_advance,
23020            line_height,
23021        } = self.character_dimensions(window);
23022
23023        let snapshot = self.snapshot(window, cx);
23024        let scroll_position = snapshot.scroll_position();
23025        let scroll_left = scroll_position.x * em_advance;
23026
23027        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23028        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23029            + self.gutter_dimensions.full_width();
23030        let y = line_height * (start.row().as_f32() - scroll_position.y);
23031
23032        Some(Bounds {
23033            origin: element_bounds.origin + point(x, y),
23034            size: size(em_width, line_height),
23035        })
23036    }
23037
23038    fn character_index_for_point(
23039        &mut self,
23040        point: gpui::Point<Pixels>,
23041        _window: &mut Window,
23042        _cx: &mut Context<Self>,
23043    ) -> Option<usize> {
23044        let position_map = self.last_position_map.as_ref()?;
23045        if !position_map.text_hitbox.contains(&point) {
23046            return None;
23047        }
23048        let display_point = position_map.point_for_position(point).previous_valid;
23049        let anchor = position_map
23050            .snapshot
23051            .display_point_to_anchor(display_point, Bias::Left);
23052        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23053        Some(utf16_offset.0)
23054    }
23055}
23056
23057trait SelectionExt {
23058    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23059    fn spanned_rows(
23060        &self,
23061        include_end_if_at_line_start: bool,
23062        map: &DisplaySnapshot,
23063    ) -> Range<MultiBufferRow>;
23064}
23065
23066impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23067    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23068        let start = self
23069            .start
23070            .to_point(&map.buffer_snapshot)
23071            .to_display_point(map);
23072        let end = self
23073            .end
23074            .to_point(&map.buffer_snapshot)
23075            .to_display_point(map);
23076        if self.reversed {
23077            end..start
23078        } else {
23079            start..end
23080        }
23081    }
23082
23083    fn spanned_rows(
23084        &self,
23085        include_end_if_at_line_start: bool,
23086        map: &DisplaySnapshot,
23087    ) -> Range<MultiBufferRow> {
23088        let start = self.start.to_point(&map.buffer_snapshot);
23089        let mut end = self.end.to_point(&map.buffer_snapshot);
23090        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23091            end.row -= 1;
23092        }
23093
23094        let buffer_start = map.prev_line_boundary(start).0;
23095        let buffer_end = map.next_line_boundary(end).0;
23096        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23097    }
23098}
23099
23100impl<T: InvalidationRegion> InvalidationStack<T> {
23101    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23102    where
23103        S: Clone + ToOffset,
23104    {
23105        while let Some(region) = self.last() {
23106            let all_selections_inside_invalidation_ranges =
23107                if selections.len() == region.ranges().len() {
23108                    selections
23109                        .iter()
23110                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23111                        .all(|(selection, invalidation_range)| {
23112                            let head = selection.head().to_offset(buffer);
23113                            invalidation_range.start <= head && invalidation_range.end >= head
23114                        })
23115                } else {
23116                    false
23117                };
23118
23119            if all_selections_inside_invalidation_ranges {
23120                break;
23121            } else {
23122                self.pop();
23123            }
23124        }
23125    }
23126}
23127
23128impl<T> Default for InvalidationStack<T> {
23129    fn default() -> Self {
23130        Self(Default::default())
23131    }
23132}
23133
23134impl<T> Deref for InvalidationStack<T> {
23135    type Target = Vec<T>;
23136
23137    fn deref(&self) -> &Self::Target {
23138        &self.0
23139    }
23140}
23141
23142impl<T> DerefMut for InvalidationStack<T> {
23143    fn deref_mut(&mut self) -> &mut Self::Target {
23144        &mut self.0
23145    }
23146}
23147
23148impl InvalidationRegion for SnippetState {
23149    fn ranges(&self) -> &[Range<Anchor>] {
23150        &self.ranges[self.active_index]
23151    }
23152}
23153
23154fn inline_completion_edit_text(
23155    current_snapshot: &BufferSnapshot,
23156    edits: &[(Range<Anchor>, String)],
23157    edit_preview: &EditPreview,
23158    include_deletions: bool,
23159    cx: &App,
23160) -> HighlightedText {
23161    let edits = edits
23162        .iter()
23163        .map(|(anchor, text)| {
23164            (
23165                anchor.start.text_anchor..anchor.end.text_anchor,
23166                text.clone(),
23167            )
23168        })
23169        .collect::<Vec<_>>();
23170
23171    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23172}
23173
23174pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23175    match severity {
23176        lsp::DiagnosticSeverity::ERROR => colors.error,
23177        lsp::DiagnosticSeverity::WARNING => colors.warning,
23178        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23179        lsp::DiagnosticSeverity::HINT => colors.info,
23180        _ => colors.ignored,
23181    }
23182}
23183
23184pub fn styled_runs_for_code_label<'a>(
23185    label: &'a CodeLabel,
23186    syntax_theme: &'a theme::SyntaxTheme,
23187) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23188    let fade_out = HighlightStyle {
23189        fade_out: Some(0.35),
23190        ..Default::default()
23191    };
23192
23193    let mut prev_end = label.filter_range.end;
23194    label
23195        .runs
23196        .iter()
23197        .enumerate()
23198        .flat_map(move |(ix, (range, highlight_id))| {
23199            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23200                style
23201            } else {
23202                return Default::default();
23203            };
23204            let mut muted_style = style;
23205            muted_style.highlight(fade_out);
23206
23207            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23208            if range.start >= label.filter_range.end {
23209                if range.start > prev_end {
23210                    runs.push((prev_end..range.start, fade_out));
23211                }
23212                runs.push((range.clone(), muted_style));
23213            } else if range.end <= label.filter_range.end {
23214                runs.push((range.clone(), style));
23215            } else {
23216                runs.push((range.start..label.filter_range.end, style));
23217                runs.push((label.filter_range.end..range.end, muted_style));
23218            }
23219            prev_end = cmp::max(prev_end, range.end);
23220
23221            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23222                runs.push((prev_end..label.text.len(), fade_out));
23223            }
23224
23225            runs
23226        })
23227}
23228
23229pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23230    let mut prev_index = 0;
23231    let mut prev_codepoint: Option<char> = None;
23232    text.char_indices()
23233        .chain([(text.len(), '\0')])
23234        .filter_map(move |(index, codepoint)| {
23235            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23236            let is_boundary = index == text.len()
23237                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23238                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23239            if is_boundary {
23240                let chunk = &text[prev_index..index];
23241                prev_index = index;
23242                Some(chunk)
23243            } else {
23244                None
23245            }
23246        })
23247}
23248
23249pub trait RangeToAnchorExt: Sized {
23250    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23251
23252    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23253        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23254        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23255    }
23256}
23257
23258impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23259    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23260        let start_offset = self.start.to_offset(snapshot);
23261        let end_offset = self.end.to_offset(snapshot);
23262        if start_offset == end_offset {
23263            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23264        } else {
23265            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23266        }
23267    }
23268}
23269
23270pub trait RowExt {
23271    fn as_f32(&self) -> f32;
23272
23273    fn next_row(&self) -> Self;
23274
23275    fn previous_row(&self) -> Self;
23276
23277    fn minus(&self, other: Self) -> u32;
23278}
23279
23280impl RowExt for DisplayRow {
23281    fn as_f32(&self) -> f32 {
23282        self.0 as f32
23283    }
23284
23285    fn next_row(&self) -> Self {
23286        Self(self.0 + 1)
23287    }
23288
23289    fn previous_row(&self) -> Self {
23290        Self(self.0.saturating_sub(1))
23291    }
23292
23293    fn minus(&self, other: Self) -> u32 {
23294        self.0 - other.0
23295    }
23296}
23297
23298impl RowExt for MultiBufferRow {
23299    fn as_f32(&self) -> f32 {
23300        self.0 as f32
23301    }
23302
23303    fn next_row(&self) -> Self {
23304        Self(self.0 + 1)
23305    }
23306
23307    fn previous_row(&self) -> Self {
23308        Self(self.0.saturating_sub(1))
23309    }
23310
23311    fn minus(&self, other: Self) -> u32 {
23312        self.0 - other.0
23313    }
23314}
23315
23316trait RowRangeExt {
23317    type Row;
23318
23319    fn len(&self) -> usize;
23320
23321    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23322}
23323
23324impl RowRangeExt for Range<MultiBufferRow> {
23325    type Row = MultiBufferRow;
23326
23327    fn len(&self) -> usize {
23328        (self.end.0 - self.start.0) as usize
23329    }
23330
23331    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23332        (self.start.0..self.end.0).map(MultiBufferRow)
23333    }
23334}
23335
23336impl RowRangeExt for Range<DisplayRow> {
23337    type Row = DisplayRow;
23338
23339    fn len(&self) -> usize {
23340        (self.end.0 - self.start.0) as usize
23341    }
23342
23343    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23344        (self.start.0..self.end.0).map(DisplayRow)
23345    }
23346}
23347
23348/// If select range has more than one line, we
23349/// just point the cursor to range.start.
23350fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23351    if range.start.row == range.end.row {
23352        range
23353    } else {
23354        range.start..range.start
23355    }
23356}
23357pub struct KillRing(ClipboardItem);
23358impl Global for KillRing {}
23359
23360const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23361
23362enum BreakpointPromptEditAction {
23363    Log,
23364    Condition,
23365    HitCondition,
23366}
23367
23368struct BreakpointPromptEditor {
23369    pub(crate) prompt: Entity<Editor>,
23370    editor: WeakEntity<Editor>,
23371    breakpoint_anchor: Anchor,
23372    breakpoint: Breakpoint,
23373    edit_action: BreakpointPromptEditAction,
23374    block_ids: HashSet<CustomBlockId>,
23375    editor_margins: Arc<Mutex<EditorMargins>>,
23376    _subscriptions: Vec<Subscription>,
23377}
23378
23379impl BreakpointPromptEditor {
23380    const MAX_LINES: u8 = 4;
23381
23382    fn new(
23383        editor: WeakEntity<Editor>,
23384        breakpoint_anchor: Anchor,
23385        breakpoint: Breakpoint,
23386        edit_action: BreakpointPromptEditAction,
23387        window: &mut Window,
23388        cx: &mut Context<Self>,
23389    ) -> Self {
23390        let base_text = match edit_action {
23391            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23392            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23393            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23394        }
23395        .map(|msg| msg.to_string())
23396        .unwrap_or_default();
23397
23398        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23399        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23400
23401        let prompt = cx.new(|cx| {
23402            let mut prompt = Editor::new(
23403                EditorMode::AutoHeight {
23404                    min_lines: 1,
23405                    max_lines: Some(Self::MAX_LINES as usize),
23406                },
23407                buffer,
23408                None,
23409                window,
23410                cx,
23411            );
23412            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23413            prompt.set_show_cursor_when_unfocused(false, cx);
23414            prompt.set_placeholder_text(
23415                match edit_action {
23416                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23417                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23418                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23419                },
23420                cx,
23421            );
23422
23423            prompt
23424        });
23425
23426        Self {
23427            prompt,
23428            editor,
23429            breakpoint_anchor,
23430            breakpoint,
23431            edit_action,
23432            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23433            block_ids: Default::default(),
23434            _subscriptions: vec![],
23435        }
23436    }
23437
23438    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23439        self.block_ids.extend(block_ids)
23440    }
23441
23442    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23443        if let Some(editor) = self.editor.upgrade() {
23444            let message = self
23445                .prompt
23446                .read(cx)
23447                .buffer
23448                .read(cx)
23449                .as_singleton()
23450                .expect("A multi buffer in breakpoint prompt isn't possible")
23451                .read(cx)
23452                .as_rope()
23453                .to_string();
23454
23455            editor.update(cx, |editor, cx| {
23456                editor.edit_breakpoint_at_anchor(
23457                    self.breakpoint_anchor,
23458                    self.breakpoint.clone(),
23459                    match self.edit_action {
23460                        BreakpointPromptEditAction::Log => {
23461                            BreakpointEditAction::EditLogMessage(message.into())
23462                        }
23463                        BreakpointPromptEditAction::Condition => {
23464                            BreakpointEditAction::EditCondition(message.into())
23465                        }
23466                        BreakpointPromptEditAction::HitCondition => {
23467                            BreakpointEditAction::EditHitCondition(message.into())
23468                        }
23469                    },
23470                    cx,
23471                );
23472
23473                editor.remove_blocks(self.block_ids.clone(), None, cx);
23474                cx.focus_self(window);
23475            });
23476        }
23477    }
23478
23479    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23480        self.editor
23481            .update(cx, |editor, cx| {
23482                editor.remove_blocks(self.block_ids.clone(), None, cx);
23483                window.focus(&editor.focus_handle);
23484            })
23485            .log_err();
23486    }
23487
23488    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23489        let settings = ThemeSettings::get_global(cx);
23490        let text_style = TextStyle {
23491            color: if self.prompt.read(cx).read_only(cx) {
23492                cx.theme().colors().text_disabled
23493            } else {
23494                cx.theme().colors().text
23495            },
23496            font_family: settings.buffer_font.family.clone(),
23497            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23498            font_size: settings.buffer_font_size(cx).into(),
23499            font_weight: settings.buffer_font.weight,
23500            line_height: relative(settings.buffer_line_height.value()),
23501            ..Default::default()
23502        };
23503        EditorElement::new(
23504            &self.prompt,
23505            EditorStyle {
23506                background: cx.theme().colors().editor_background,
23507                local_player: cx.theme().players().local(),
23508                text: text_style,
23509                ..Default::default()
23510            },
23511        )
23512    }
23513}
23514
23515impl Render for BreakpointPromptEditor {
23516    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23517        let editor_margins = *self.editor_margins.lock();
23518        let gutter_dimensions = editor_margins.gutter;
23519        h_flex()
23520            .key_context("Editor")
23521            .bg(cx.theme().colors().editor_background)
23522            .border_y_1()
23523            .border_color(cx.theme().status().info_border)
23524            .size_full()
23525            .py(window.line_height() / 2.5)
23526            .on_action(cx.listener(Self::confirm))
23527            .on_action(cx.listener(Self::cancel))
23528            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23529            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23530    }
23531}
23532
23533impl Focusable for BreakpointPromptEditor {
23534    fn focus_handle(&self, cx: &App) -> FocusHandle {
23535        self.prompt.focus_handle(cx)
23536    }
23537}
23538
23539fn all_edits_insertions_or_deletions(
23540    edits: &Vec<(Range<Anchor>, String)>,
23541    snapshot: &MultiBufferSnapshot,
23542) -> bool {
23543    let mut all_insertions = true;
23544    let mut all_deletions = true;
23545
23546    for (range, new_text) in edits.iter() {
23547        let range_is_empty = range.to_offset(&snapshot).is_empty();
23548        let text_is_empty = new_text.is_empty();
23549
23550        if range_is_empty != text_is_empty {
23551            if range_is_empty {
23552                all_deletions = false;
23553            } else {
23554                all_insertions = false;
23555            }
23556        } else {
23557            return false;
23558        }
23559
23560        if !all_insertions && !all_deletions {
23561            return false;
23562        }
23563    }
23564    all_insertions || all_deletions
23565}
23566
23567struct MissingEditPredictionKeybindingTooltip;
23568
23569impl Render for MissingEditPredictionKeybindingTooltip {
23570    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23571        ui::tooltip_container(window, cx, |container, _, cx| {
23572            container
23573                .flex_shrink_0()
23574                .max_w_80()
23575                .min_h(rems_from_px(124.))
23576                .justify_between()
23577                .child(
23578                    v_flex()
23579                        .flex_1()
23580                        .text_ui_sm(cx)
23581                        .child(Label::new("Conflict with Accept Keybinding"))
23582                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23583                )
23584                .child(
23585                    h_flex()
23586                        .pb_1()
23587                        .gap_1()
23588                        .items_end()
23589                        .w_full()
23590                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23591                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23592                        }))
23593                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23594                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23595                        })),
23596                )
23597        })
23598    }
23599}
23600
23601#[derive(Debug, Clone, Copy, PartialEq)]
23602pub struct LineHighlight {
23603    pub background: Background,
23604    pub border: Option<gpui::Hsla>,
23605    pub include_gutter: bool,
23606    pub type_id: Option<TypeId>,
23607}
23608
23609struct LineManipulationResult {
23610    pub new_text: String,
23611    pub line_count_before: usize,
23612    pub line_count_after: usize,
23613}
23614
23615fn render_diff_hunk_controls(
23616    row: u32,
23617    status: &DiffHunkStatus,
23618    hunk_range: Range<Anchor>,
23619    is_created_file: bool,
23620    line_height: Pixels,
23621    editor: &Entity<Editor>,
23622    _window: &mut Window,
23623    cx: &mut App,
23624) -> AnyElement {
23625    h_flex()
23626        .h(line_height)
23627        .mr_1()
23628        .gap_1()
23629        .px_0p5()
23630        .pb_1()
23631        .border_x_1()
23632        .border_b_1()
23633        .border_color(cx.theme().colors().border_variant)
23634        .rounded_b_lg()
23635        .bg(cx.theme().colors().editor_background)
23636        .gap_1()
23637        .block_mouse_except_scroll()
23638        .shadow_md()
23639        .child(if status.has_secondary_hunk() {
23640            Button::new(("stage", row as u64), "Stage")
23641                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23642                .tooltip({
23643                    let focus_handle = editor.focus_handle(cx);
23644                    move |window, cx| {
23645                        Tooltip::for_action_in(
23646                            "Stage Hunk",
23647                            &::git::ToggleStaged,
23648                            &focus_handle,
23649                            window,
23650                            cx,
23651                        )
23652                    }
23653                })
23654                .on_click({
23655                    let editor = editor.clone();
23656                    move |_event, _window, cx| {
23657                        editor.update(cx, |editor, cx| {
23658                            editor.stage_or_unstage_diff_hunks(
23659                                true,
23660                                vec![hunk_range.start..hunk_range.start],
23661                                cx,
23662                            );
23663                        });
23664                    }
23665                })
23666        } else {
23667            Button::new(("unstage", row as u64), "Unstage")
23668                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23669                .tooltip({
23670                    let focus_handle = editor.focus_handle(cx);
23671                    move |window, cx| {
23672                        Tooltip::for_action_in(
23673                            "Unstage Hunk",
23674                            &::git::ToggleStaged,
23675                            &focus_handle,
23676                            window,
23677                            cx,
23678                        )
23679                    }
23680                })
23681                .on_click({
23682                    let editor = editor.clone();
23683                    move |_event, _window, cx| {
23684                        editor.update(cx, |editor, cx| {
23685                            editor.stage_or_unstage_diff_hunks(
23686                                false,
23687                                vec![hunk_range.start..hunk_range.start],
23688                                cx,
23689                            );
23690                        });
23691                    }
23692                })
23693        })
23694        .child(
23695            Button::new(("restore", row as u64), "Restore")
23696                .tooltip({
23697                    let focus_handle = editor.focus_handle(cx);
23698                    move |window, cx| {
23699                        Tooltip::for_action_in(
23700                            "Restore Hunk",
23701                            &::git::Restore,
23702                            &focus_handle,
23703                            window,
23704                            cx,
23705                        )
23706                    }
23707                })
23708                .on_click({
23709                    let editor = editor.clone();
23710                    move |_event, window, cx| {
23711                        editor.update(cx, |editor, cx| {
23712                            let snapshot = editor.snapshot(window, cx);
23713                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23714                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23715                        });
23716                    }
23717                })
23718                .disabled(is_created_file),
23719        )
23720        .when(
23721            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23722            |el| {
23723                el.child(
23724                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23725                        .shape(IconButtonShape::Square)
23726                        .icon_size(IconSize::Small)
23727                        // .disabled(!has_multiple_hunks)
23728                        .tooltip({
23729                            let focus_handle = editor.focus_handle(cx);
23730                            move |window, cx| {
23731                                Tooltip::for_action_in(
23732                                    "Next Hunk",
23733                                    &GoToHunk,
23734                                    &focus_handle,
23735                                    window,
23736                                    cx,
23737                                )
23738                            }
23739                        })
23740                        .on_click({
23741                            let editor = editor.clone();
23742                            move |_event, window, cx| {
23743                                editor.update(cx, |editor, cx| {
23744                                    let snapshot = editor.snapshot(window, cx);
23745                                    let position =
23746                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23747                                    editor.go_to_hunk_before_or_after_position(
23748                                        &snapshot,
23749                                        position,
23750                                        Direction::Next,
23751                                        window,
23752                                        cx,
23753                                    );
23754                                    editor.expand_selected_diff_hunks(cx);
23755                                });
23756                            }
23757                        }),
23758                )
23759                .child(
23760                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23761                        .shape(IconButtonShape::Square)
23762                        .icon_size(IconSize::Small)
23763                        // .disabled(!has_multiple_hunks)
23764                        .tooltip({
23765                            let focus_handle = editor.focus_handle(cx);
23766                            move |window, cx| {
23767                                Tooltip::for_action_in(
23768                                    "Previous Hunk",
23769                                    &GoToPreviousHunk,
23770                                    &focus_handle,
23771                                    window,
23772                                    cx,
23773                                )
23774                            }
23775                        })
23776                        .on_click({
23777                            let editor = editor.clone();
23778                            move |_event, window, cx| {
23779                                editor.update(cx, |editor, cx| {
23780                                    let snapshot = editor.snapshot(window, cx);
23781                                    let point =
23782                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23783                                    editor.go_to_hunk_before_or_after_position(
23784                                        &snapshot,
23785                                        point,
23786                                        Direction::Prev,
23787                                        window,
23788                                        cx,
23789                                    );
23790                                    editor.expand_selected_diff_hunks(cx);
23791                                });
23792                            }
23793                        }),
23794                )
23795            },
23796        )
23797        .into_any_element()
23798}