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 edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269struct InlineValueCache {
  270    enabled: bool,
  271    inlays: Vec<InlayId>,
  272    refresh_task: Task<Option<()>>,
  273}
  274
  275impl InlineValueCache {
  276    fn new(enabled: bool) -> Self {
  277        Self {
  278            enabled,
  279            inlays: Vec::new(),
  280            refresh_task: Task::ready(None),
  281        }
  282    }
  283}
  284
  285#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  286pub enum InlayId {
  287    EditPrediction(usize),
  288    DebuggerValue(usize),
  289    // LSP
  290    Hint(usize),
  291    Color(usize),
  292}
  293
  294impl InlayId {
  295    fn id(&self) -> usize {
  296        match self {
  297            Self::EditPrediction(id) => *id,
  298            Self::DebuggerValue(id) => *id,
  299            Self::Hint(id) => *id,
  300            Self::Color(id) => *id,
  301        }
  302    }
  303}
  304
  305pub enum ActiveDebugLine {}
  306pub enum DebugStackFrameLine {}
  307enum DocumentHighlightRead {}
  308enum DocumentHighlightWrite {}
  309enum InputComposition {}
  310pub enum PendingInput {}
  311enum SelectedTextHighlight {}
  312
  313pub enum ConflictsOuter {}
  314pub enum ConflictsOurs {}
  315pub enum ConflictsTheirs {}
  316pub enum ConflictsOursMarker {}
  317pub enum ConflictsTheirsMarker {}
  318
  319#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  320pub enum Navigated {
  321    Yes,
  322    No,
  323}
  324
  325impl Navigated {
  326    pub fn from_bool(yes: bool) -> Navigated {
  327        if yes { Navigated::Yes } else { Navigated::No }
  328    }
  329}
  330
  331#[derive(Debug, Clone, PartialEq, Eq)]
  332enum DisplayDiffHunk {
  333    Folded {
  334        display_row: DisplayRow,
  335    },
  336    Unfolded {
  337        is_created_file: bool,
  338        diff_base_byte_range: Range<usize>,
  339        display_row_range: Range<DisplayRow>,
  340        multi_buffer_range: Range<Anchor>,
  341        status: DiffHunkStatus,
  342    },
  343}
  344
  345pub enum HideMouseCursorOrigin {
  346    TypingAction,
  347    MovementAction,
  348}
  349
  350pub fn init_settings(cx: &mut App) {
  351    EditorSettings::register(cx);
  352}
  353
  354pub fn init(cx: &mut App) {
  355    init_settings(cx);
  356
  357    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  358
  359    workspace::register_project_item::<Editor>(cx);
  360    workspace::FollowableViewRegistry::register::<Editor>(cx);
  361    workspace::register_serializable_item::<Editor>(cx);
  362
  363    cx.observe_new(
  364        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  365            workspace.register_action(Editor::new_file);
  366            workspace.register_action(Editor::new_file_vertical);
  367            workspace.register_action(Editor::new_file_horizontal);
  368            workspace.register_action(Editor::cancel_language_server_work);
  369            workspace.register_action(Editor::toggle_focus);
  370        },
  371    )
  372    .detach();
  373
  374    cx.on_action(move |_: &workspace::NewFile, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388    cx.on_action(move |_: &workspace::NewWindow, cx| {
  389        let app_state = workspace::AppState::global(cx);
  390        if let Some(app_state) = app_state.upgrade() {
  391            workspace::open_new(
  392                Default::default(),
  393                app_state,
  394                cx,
  395                |workspace, window, cx| {
  396                    cx.activate(true);
  397                    Editor::new_file(workspace, &Default::default(), window, cx)
  398                },
  399            )
  400            .detach();
  401        }
  402    });
  403}
  404
  405pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  406    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  407}
  408
  409pub trait DiagnosticRenderer {
  410    fn render_group(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        buffer_id: BufferId,
  414        snapshot: EditorSnapshot,
  415        editor: WeakEntity<Editor>,
  416        cx: &mut App,
  417    ) -> Vec<BlockProperties<Anchor>>;
  418
  419    fn render_hover(
  420        &self,
  421        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  422        range: Range<Point>,
  423        buffer_id: BufferId,
  424        cx: &mut App,
  425    ) -> Option<Entity<markdown::Markdown>>;
  426
  427    fn open_link(
  428        &self,
  429        editor: &mut Editor,
  430        link: SharedString,
  431        window: &mut Window,
  432        cx: &mut Context<Editor>,
  433    );
  434}
  435
  436pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  437
  438impl GlobalDiagnosticRenderer {
  439    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  440        cx.try_global::<Self>().map(|g| g.0.clone())
  441    }
  442}
  443
  444impl gpui::Global for GlobalDiagnosticRenderer {}
  445pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  446    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  447}
  448
  449pub struct SearchWithinRange;
  450
  451trait InvalidationRegion {
  452    fn ranges(&self) -> &[Range<Anchor>];
  453}
  454
  455#[derive(Clone, Debug, PartialEq)]
  456pub enum SelectPhase {
  457    Begin {
  458        position: DisplayPoint,
  459        add: bool,
  460        click_count: usize,
  461    },
  462    BeginColumnar {
  463        position: DisplayPoint,
  464        reset: bool,
  465        mode: ColumnarMode,
  466        goal_column: u32,
  467    },
  468    Extend {
  469        position: DisplayPoint,
  470        click_count: usize,
  471    },
  472    Update {
  473        position: DisplayPoint,
  474        goal_column: u32,
  475        scroll_delta: gpui::Point<f32>,
  476    },
  477    End,
  478}
  479
  480#[derive(Clone, Debug, PartialEq)]
  481pub enum ColumnarMode {
  482    FromMouse,
  483    FromSelection,
  484}
  485
  486#[derive(Clone, Debug)]
  487pub enum SelectMode {
  488    Character,
  489    Word(Range<Anchor>),
  490    Line(Range<Anchor>),
  491    All,
  492}
  493
  494#[derive(Clone, PartialEq, Eq, Debug)]
  495pub enum EditorMode {
  496    SingleLine,
  497    AutoHeight {
  498        min_lines: usize,
  499        max_lines: Option<usize>,
  500    },
  501    Full {
  502        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  503        scale_ui_elements_with_buffer_font_size: bool,
  504        /// When set to `true`, the editor will render a background for the active line.
  505        show_active_line_background: bool,
  506        /// When set to `true`, the editor's height will be determined by its content.
  507        sized_by_content: bool,
  508    },
  509    Minimap {
  510        parent: WeakEntity<Editor>,
  511    },
  512}
  513
  514impl EditorMode {
  515    pub fn full() -> Self {
  516        Self::Full {
  517            scale_ui_elements_with_buffer_font_size: true,
  518            show_active_line_background: true,
  519            sized_by_content: false,
  520        }
  521    }
  522
  523    #[inline]
  524    pub fn is_full(&self) -> bool {
  525        matches!(self, Self::Full { .. })
  526    }
  527
  528    #[inline]
  529    pub fn is_single_line(&self) -> bool {
  530        matches!(self, Self::SingleLine { .. })
  531    }
  532
  533    #[inline]
  534    fn is_minimap(&self) -> bool {
  535        matches!(self, Self::Minimap { .. })
  536    }
  537}
  538
  539#[derive(Copy, Clone, Debug)]
  540pub enum SoftWrap {
  541    /// Prefer not to wrap at all.
  542    ///
  543    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  544    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  545    GitDiff,
  546    /// Prefer a single line generally, unless an overly long line is encountered.
  547    None,
  548    /// Soft wrap lines that exceed the editor width.
  549    EditorWidth,
  550    /// Soft wrap lines at the preferred line length.
  551    Column(u32),
  552    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  553    Bounded(u32),
  554}
  555
  556#[derive(Clone)]
  557pub struct EditorStyle {
  558    pub background: Hsla,
  559    pub border: Hsla,
  560    pub local_player: PlayerColor,
  561    pub text: TextStyle,
  562    pub scrollbar_width: Pixels,
  563    pub syntax: Arc<SyntaxTheme>,
  564    pub status: StatusColors,
  565    pub inlay_hints_style: HighlightStyle,
  566    pub edit_prediction_styles: EditPredictionStyles,
  567    pub unnecessary_code_fade: f32,
  568    pub show_underlines: bool,
  569}
  570
  571impl Default for EditorStyle {
  572    fn default() -> Self {
  573        Self {
  574            background: Hsla::default(),
  575            border: Hsla::default(),
  576            local_player: PlayerColor::default(),
  577            text: TextStyle::default(),
  578            scrollbar_width: Pixels::default(),
  579            syntax: Default::default(),
  580            // HACK: Status colors don't have a real default.
  581            // We should look into removing the status colors from the editor
  582            // style and retrieve them directly from the theme.
  583            status: StatusColors::dark(),
  584            inlay_hints_style: HighlightStyle::default(),
  585            edit_prediction_styles: EditPredictionStyles {
  586                insertion: HighlightStyle::default(),
  587                whitespace: HighlightStyle::default(),
  588            },
  589            unnecessary_code_fade: Default::default(),
  590            show_underlines: true,
  591        }
  592    }
  593}
  594
  595pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  596    let show_background = language_settings::language_settings(None, None, cx)
  597        .inlay_hints
  598        .show_background;
  599
  600    HighlightStyle {
  601        color: Some(cx.theme().status().hint),
  602        background_color: show_background.then(|| cx.theme().status().hint_background),
  603        ..HighlightStyle::default()
  604    }
  605}
  606
  607pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  608    EditPredictionStyles {
  609        insertion: HighlightStyle {
  610            color: Some(cx.theme().status().predictive),
  611            ..HighlightStyle::default()
  612        },
  613        whitespace: HighlightStyle {
  614            background_color: Some(cx.theme().status().created_background),
  615            ..HighlightStyle::default()
  616        },
  617    }
  618}
  619
  620type CompletionId = usize;
  621
  622pub(crate) enum EditDisplayMode {
  623    TabAccept,
  624    DiffPopover,
  625    Inline,
  626}
  627
  628enum EditPrediction {
  629    Edit {
  630        edits: Vec<(Range<Anchor>, String)>,
  631        edit_preview: Option<EditPreview>,
  632        display_mode: EditDisplayMode,
  633        snapshot: BufferSnapshot,
  634    },
  635    Move {
  636        target: Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Range<Anchor>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  730type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  731
  732#[derive(Default)]
  733struct ScrollbarMarkerState {
  734    scrollbar_size: Size<Pixels>,
  735    dirty: bool,
  736    markers: Arc<[PaintQuad]>,
  737    pending_refresh: Option<Task<Result<()>>>,
  738}
  739
  740impl ScrollbarMarkerState {
  741    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  742        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  743    }
  744}
  745
  746#[derive(Clone, Copy, PartialEq, Eq)]
  747pub enum MinimapVisibility {
  748    Disabled,
  749    Enabled {
  750        /// The configuration currently present in the users settings.
  751        setting_configuration: bool,
  752        /// Whether to override the currently set visibility from the users setting.
  753        toggle_override: bool,
  754    },
  755}
  756
  757impl MinimapVisibility {
  758    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  759        if mode.is_full() {
  760            Self::Enabled {
  761                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  762                toggle_override: false,
  763            }
  764        } else {
  765            Self::Disabled
  766        }
  767    }
  768
  769    fn hidden(&self) -> Self {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                ..
  774            } => Self::Enabled {
  775                setting_configuration,
  776                toggle_override: setting_configuration,
  777            },
  778            Self::Disabled => Self::Disabled,
  779        }
  780    }
  781
  782    fn disabled(&self) -> bool {
  783        matches!(*self, Self::Disabled)
  784    }
  785
  786    fn settings_visibility(&self) -> bool {
  787        match *self {
  788            Self::Enabled {
  789                setting_configuration,
  790                ..
  791            } => setting_configuration,
  792            _ => false,
  793        }
  794    }
  795
  796    fn visible(&self) -> bool {
  797        match *self {
  798            Self::Enabled {
  799                setting_configuration,
  800                toggle_override,
  801            } => setting_configuration ^ toggle_override,
  802            _ => false,
  803        }
  804    }
  805
  806    fn toggle_visibility(&self) -> Self {
  807        match *self {
  808            Self::Enabled {
  809                toggle_override,
  810                setting_configuration,
  811            } => Self::Enabled {
  812                setting_configuration,
  813                toggle_override: !toggle_override,
  814            },
  815            Self::Disabled => Self::Disabled,
  816        }
  817    }
  818}
  819
  820#[derive(Clone, Debug)]
  821struct RunnableTasks {
  822    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  823    offset: multi_buffer::Anchor,
  824    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  825    column: u32,
  826    // Values of all named captures, including those starting with '_'
  827    extra_variables: HashMap<String, String>,
  828    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  829    context_range: Range<BufferOffset>,
  830}
  831
  832impl RunnableTasks {
  833    fn resolve<'a>(
  834        &'a self,
  835        cx: &'a task::TaskContext,
  836    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  837        self.templates.iter().filter_map(|(kind, template)| {
  838            template
  839                .resolve_task(&kind.to_id_base(), cx)
  840                .map(|task| (kind.clone(), task))
  841        })
  842    }
  843}
  844
  845#[derive(Clone)]
  846pub struct ResolvedTasks {
  847    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  848    position: Anchor,
  849}
  850
  851#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  852struct BufferOffset(usize);
  853
  854// Addons allow storing per-editor state in other crates (e.g. Vim)
  855pub trait Addon: 'static {
  856    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  857
  858    fn render_buffer_header_controls(
  859        &self,
  860        _: &ExcerptInfo,
  861        _: &Window,
  862        _: &App,
  863    ) -> Option<AnyElement> {
  864        None
  865    }
  866
  867    fn to_any(&self) -> &dyn std::any::Any;
  868
  869    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  870        None
  871    }
  872}
  873
  874struct ChangeLocation {
  875    current: Option<Vec<Anchor>>,
  876    original: Vec<Anchor>,
  877}
  878impl ChangeLocation {
  879    fn locations(&self) -> &[Anchor] {
  880        self.current.as_ref().unwrap_or(&self.original)
  881    }
  882}
  883
  884/// A set of caret positions, registered when the editor was edited.
  885pub struct ChangeList {
  886    changes: Vec<ChangeLocation>,
  887    /// Currently "selected" change.
  888    position: Option<usize>,
  889}
  890
  891impl ChangeList {
  892    pub fn new() -> Self {
  893        Self {
  894            changes: Vec::new(),
  895            position: None,
  896        }
  897    }
  898
  899    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  900    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  901    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  902        if self.changes.is_empty() {
  903            return None;
  904        }
  905
  906        let prev = self.position.unwrap_or(self.changes.len());
  907        let next = if direction == Direction::Prev {
  908            prev.saturating_sub(count)
  909        } else {
  910            (prev + count).min(self.changes.len() - 1)
  911        };
  912        self.position = Some(next);
  913        self.changes.get(next).map(|change| change.locations())
  914    }
  915
  916    /// Adds a new change to the list, resetting the change list position.
  917    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  918        self.position.take();
  919        if let Some(last) = self.changes.last_mut()
  920            && group
  921        {
  922            last.current = Some(new_positions)
  923        } else {
  924            self.changes.push(ChangeLocation {
  925                original: new_positions,
  926                current: None,
  927            });
  928        }
  929    }
  930
  931    pub fn last(&self) -> Option<&[Anchor]> {
  932        self.changes.last().map(|change| change.locations())
  933    }
  934
  935    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  936        self.changes.last().map(|change| change.original.as_slice())
  937    }
  938
  939    pub fn invert_last_group(&mut self) {
  940        if let Some(last) = self.changes.last_mut()
  941            && let Some(current) = last.current.as_mut()
  942        {
  943            mem::swap(&mut last.original, current);
  944        }
  945    }
  946}
  947
  948#[derive(Clone)]
  949struct InlineBlamePopoverState {
  950    scroll_handle: ScrollHandle,
  951    commit_message: Option<ParsedCommitMessage>,
  952    markdown: Entity<Markdown>,
  953}
  954
  955struct InlineBlamePopover {
  956    position: gpui::Point<Pixels>,
  957    hide_task: Option<Task<()>>,
  958    popover_bounds: Option<Bounds<Pixels>>,
  959    popover_state: InlineBlamePopoverState,
  960    keyboard_grace: bool,
  961}
  962
  963enum SelectionDragState {
  964    /// State when no drag related activity is detected.
  965    None,
  966    /// State when the mouse is down on a selection that is about to be dragged.
  967    ReadyToDrag {
  968        selection: Selection<Anchor>,
  969        click_position: gpui::Point<Pixels>,
  970        mouse_down_time: Instant,
  971    },
  972    /// State when the mouse is dragging the selection in the editor.
  973    Dragging {
  974        selection: Selection<Anchor>,
  975        drop_cursor: Selection<Anchor>,
  976        hide_drop_cursor: bool,
  977    },
  978}
  979
  980enum ColumnarSelectionState {
  981    FromMouse {
  982        selection_tail: Anchor,
  983        display_point: Option<DisplayPoint>,
  984    },
  985    FromSelection {
  986        selection_tail: Anchor,
  987    },
  988}
  989
  990/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  991/// a breakpoint on them.
  992#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  993struct PhantomBreakpointIndicator {
  994    display_row: DisplayRow,
  995    /// There's a small debounce between hovering over the line and showing the indicator.
  996    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  997    is_active: bool,
  998    collides_with_existing_breakpoint: bool,
  999}
 1000
 1001/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1002///
 1003/// See the [module level documentation](self) for more information.
 1004pub struct Editor {
 1005    focus_handle: FocusHandle,
 1006    last_focused_descendant: Option<WeakFocusHandle>,
 1007    /// The text buffer being edited
 1008    buffer: Entity<MultiBuffer>,
 1009    /// Map of how text in the buffer should be displayed.
 1010    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1011    pub display_map: Entity<DisplayMap>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    placeholder_text: Option<Arc<str>>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    collapse_matches: bool,
 1090    autoindent_mode: Option<AutoindentMode>,
 1091    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1092    input_enabled: bool,
 1093    use_modal_editing: bool,
 1094    read_only: bool,
 1095    leader_id: Option<CollaboratorId>,
 1096    remote_id: Option<ViewId>,
 1097    pub hover_state: HoverState,
 1098    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1099    gutter_hovered: bool,
 1100    hovered_link_state: Option<HoveredLinkState>,
 1101    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1102    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1103    active_edit_prediction: Option<EditPredictionState>,
 1104    /// Used to prevent flickering as the user types while the menu is open
 1105    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1106    edit_prediction_settings: EditPredictionSettings,
 1107    edit_predictions_hidden_for_vim_mode: bool,
 1108    show_edit_predictions_override: Option<bool>,
 1109    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1110    edit_prediction_preview: EditPredictionPreview,
 1111    edit_prediction_indent_conflict: bool,
 1112    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1113    inlay_hint_cache: InlayHintCache,
 1114    next_inlay_id: usize,
 1115    _subscriptions: Vec<Subscription>,
 1116    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1117    gutter_dimensions: GutterDimensions,
 1118    style: Option<EditorStyle>,
 1119    text_style_refinement: Option<TextStyleRefinement>,
 1120    next_editor_action_id: EditorActionId,
 1121    editor_actions: Rc<
 1122        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1123    >,
 1124    use_autoclose: bool,
 1125    use_auto_surround: bool,
 1126    auto_replace_emoji_shortcode: bool,
 1127    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1128    show_git_blame_gutter: bool,
 1129    show_git_blame_inline: bool,
 1130    show_git_blame_inline_delay_task: Option<Task<()>>,
 1131    git_blame_inline_enabled: bool,
 1132    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1133    serialize_dirty_buffers: bool,
 1134    show_selection_menu: Option<bool>,
 1135    blame: Option<Entity<GitBlame>>,
 1136    blame_subscription: Option<Subscription>,
 1137    custom_context_menu: Option<
 1138        Box<
 1139            dyn 'static
 1140                + Fn(
 1141                    &mut Self,
 1142                    DisplayPoint,
 1143                    &mut Window,
 1144                    &mut Context<Self>,
 1145                ) -> Option<Entity<ui::ContextMenu>>,
 1146        >,
 1147    >,
 1148    last_bounds: Option<Bounds<Pixels>>,
 1149    last_position_map: Option<Rc<PositionMap>>,
 1150    expect_bounds_change: Option<Bounds<Pixels>>,
 1151    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1152    tasks_update_task: Option<Task<()>>,
 1153    breakpoint_store: Option<Entity<BreakpointStore>>,
 1154    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1155    hovered_diff_hunk_row: Option<DisplayRow>,
 1156    pull_diagnostics_task: Task<()>,
 1157    in_project_search: bool,
 1158    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1159    breadcrumb_header: Option<String>,
 1160    focused_block: Option<FocusedBlock>,
 1161    next_scroll_position: NextScrollCursorCenterTopBottom,
 1162    addons: HashMap<TypeId, Box<dyn Addon>>,
 1163    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1164    load_diff_task: Option<Shared<Task<()>>>,
 1165    /// Whether we are temporarily displaying a diff other than git's
 1166    temporary_diff_override: bool,
 1167    selection_mark_mode: bool,
 1168    toggle_fold_multiple_buffers: Task<()>,
 1169    _scroll_cursor_center_top_bottom_task: Task<()>,
 1170    serialize_selections: Task<()>,
 1171    serialize_folds: Task<()>,
 1172    mouse_cursor_hidden: bool,
 1173    minimap: Option<Entity<Self>>,
 1174    hide_mouse_mode: HideMouseMode,
 1175    pub change_list: ChangeList,
 1176    inline_value_cache: InlineValueCache,
 1177    selection_drag_state: SelectionDragState,
 1178    next_color_inlay_id: usize,
 1179    colors: Option<LspColorData>,
 1180    folding_newlines: Task<()>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_text: Option<Arc<str>>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: true,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901                    _ => {}
 1902                },
 1903            ));
 1904            if let Some(task_inventory) = project
 1905                .read(cx)
 1906                .task_store()
 1907                .read(cx)
 1908                .task_inventory()
 1909                .cloned()
 1910            {
 1911                project_subscriptions.push(cx.observe_in(
 1912                    &task_inventory,
 1913                    window,
 1914                    |editor, _, window, cx| {
 1915                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1916                    },
 1917                ));
 1918            };
 1919
 1920            project_subscriptions.push(cx.subscribe_in(
 1921                &project.read(cx).breakpoint_store(),
 1922                window,
 1923                |editor, _, event, window, cx| match event {
 1924                    BreakpointStoreEvent::ClearDebugLines => {
 1925                        editor.clear_row_highlights::<ActiveDebugLine>();
 1926                        editor.refresh_inline_values(cx);
 1927                    }
 1928                    BreakpointStoreEvent::SetDebugLine => {
 1929                        if editor.go_to_active_debug_line(window, cx) {
 1930                            cx.stop_propagation();
 1931                        }
 1932
 1933                        editor.refresh_inline_values(cx);
 1934                    }
 1935                    _ => {}
 1936                },
 1937            ));
 1938            let git_store = project.read(cx).git_store().clone();
 1939            let project = project.clone();
 1940            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1941                if let GitStoreEvent::RepositoryUpdated(
 1942                    _,
 1943                    RepositoryEvent::Updated {
 1944                        new_instance: true, ..
 1945                    },
 1946                    _,
 1947                ) = event
 1948                {
 1949                    this.load_diff_task = Some(
 1950                        update_uncommitted_diff_for_buffer(
 1951                            cx.entity(),
 1952                            &project,
 1953                            this.buffer.read(cx).all_buffers(),
 1954                            this.buffer.clone(),
 1955                            cx,
 1956                        )
 1957                        .shared(),
 1958                    );
 1959                }
 1960            }));
 1961        }
 1962
 1963        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1964
 1965        let inlay_hint_settings =
 1966            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1967        let focus_handle = cx.focus_handle();
 1968        if !is_minimap {
 1969            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1970                .detach();
 1971            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1972                .detach();
 1973            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1974                .detach();
 1975            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1976                .detach();
 1977            cx.observe_pending_input(window, Self::observe_pending_input)
 1978                .detach();
 1979        }
 1980
 1981        let show_indent_guides =
 1982            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 1983                Some(false)
 1984            } else {
 1985                None
 1986            };
 1987
 1988        let breakpoint_store = match (&mode, project.as_ref()) {
 1989            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1990            _ => None,
 1991        };
 1992
 1993        let mut code_action_providers = Vec::new();
 1994        let mut load_uncommitted_diff = None;
 1995        if let Some(project) = project.clone() {
 1996            load_uncommitted_diff = Some(
 1997                update_uncommitted_diff_for_buffer(
 1998                    cx.entity(),
 1999                    &project,
 2000                    buffer.read(cx).all_buffers(),
 2001                    buffer.clone(),
 2002                    cx,
 2003                )
 2004                .shared(),
 2005            );
 2006            code_action_providers.push(Rc::new(project) as Rc<_>);
 2007        }
 2008
 2009        let mut editor = Self {
 2010            focus_handle,
 2011            show_cursor_when_unfocused: false,
 2012            last_focused_descendant: None,
 2013            buffer: buffer.clone(),
 2014            display_map: display_map.clone(),
 2015            selections,
 2016            scroll_manager: ScrollManager::new(cx),
 2017            columnar_selection_state: None,
 2018            add_selections_state: None,
 2019            select_next_state: None,
 2020            select_prev_state: None,
 2021            selection_history: SelectionHistory::default(),
 2022            defer_selection_effects: false,
 2023            deferred_selection_effects_state: None,
 2024            autoclose_regions: Vec::new(),
 2025            snippet_stack: InvalidationStack::default(),
 2026            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2027            ime_transaction: None,
 2028            active_diagnostics: ActiveDiagnostic::None,
 2029            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2030            inline_diagnostics_update: Task::ready(()),
 2031            inline_diagnostics: Vec::new(),
 2032            soft_wrap_mode_override,
 2033            diagnostics_max_severity,
 2034            hard_wrap: None,
 2035            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2037            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2038            project,
 2039            blink_manager: blink_manager.clone(),
 2040            show_local_selections: true,
 2041            show_scrollbars: ScrollbarAxes {
 2042                horizontal: full_mode,
 2043                vertical: full_mode,
 2044            },
 2045            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2046            offset_content: !matches!(mode, EditorMode::SingleLine),
 2047            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2048            show_gutter: full_mode,
 2049            show_line_numbers: (!full_mode).then_some(false),
 2050            use_relative_line_numbers: None,
 2051            disable_expand_excerpt_buttons: !full_mode,
 2052            show_git_diff_gutter: None,
 2053            show_code_actions: None,
 2054            show_runnables: None,
 2055            show_breakpoints: None,
 2056            show_wrap_guides: None,
 2057            show_indent_guides,
 2058            placeholder_text: None,
 2059            highlight_order: 0,
 2060            highlighted_rows: HashMap::default(),
 2061            background_highlights: TreeMap::default(),
 2062            gutter_highlights: TreeMap::default(),
 2063            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2064            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2065            nav_history: None,
 2066            context_menu: RefCell::new(None),
 2067            context_menu_options: None,
 2068            mouse_context_menu: None,
 2069            completion_tasks: Vec::new(),
 2070            inline_blame_popover: None,
 2071            inline_blame_popover_show_task: None,
 2072            signature_help_state: SignatureHelpState::default(),
 2073            auto_signature_help: None,
 2074            find_all_references_task_sources: Vec::new(),
 2075            next_completion_id: 0,
 2076            next_inlay_id: 0,
 2077            code_action_providers,
 2078            available_code_actions: None,
 2079            code_actions_task: None,
 2080            quick_selection_highlight_task: None,
 2081            debounced_selection_highlight_task: None,
 2082            document_highlights_task: None,
 2083            linked_editing_range_task: None,
 2084            pending_rename: None,
 2085            searchable: !is_minimap,
 2086            cursor_shape: EditorSettings::get_global(cx)
 2087                .cursor_shape
 2088                .unwrap_or_default(),
 2089            current_line_highlight: None,
 2090            autoindent_mode: Some(AutoindentMode::EachLine),
 2091            collapse_matches: false,
 2092            workspace: None,
 2093            input_enabled: !is_minimap,
 2094            use_modal_editing: full_mode,
 2095            read_only: is_minimap,
 2096            use_autoclose: true,
 2097            use_auto_surround: true,
 2098            auto_replace_emoji_shortcode: false,
 2099            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2100            leader_id: None,
 2101            remote_id: None,
 2102            hover_state: HoverState::default(),
 2103            pending_mouse_down: None,
 2104            hovered_link_state: None,
 2105            edit_prediction_provider: None,
 2106            active_edit_prediction: None,
 2107            stale_edit_prediction_in_menu: None,
 2108            edit_prediction_preview: EditPredictionPreview::Inactive {
 2109                released_too_fast: false,
 2110            },
 2111            inline_diagnostics_enabled: full_mode,
 2112            diagnostics_enabled: full_mode,
 2113            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2114            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2115            gutter_hovered: false,
 2116            pixel_position_of_newest_cursor: None,
 2117            last_bounds: None,
 2118            last_position_map: None,
 2119            expect_bounds_change: None,
 2120            gutter_dimensions: GutterDimensions::default(),
 2121            style: None,
 2122            show_cursor_names: false,
 2123            hovered_cursors: HashMap::default(),
 2124            next_editor_action_id: EditorActionId::default(),
 2125            editor_actions: Rc::default(),
 2126            edit_predictions_hidden_for_vim_mode: false,
 2127            show_edit_predictions_override: None,
 2128            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2129            edit_prediction_settings: EditPredictionSettings::Disabled,
 2130            edit_prediction_indent_conflict: false,
 2131            edit_prediction_requires_modifier_in_indent_conflict: true,
 2132            custom_context_menu: None,
 2133            show_git_blame_gutter: false,
 2134            show_git_blame_inline: false,
 2135            show_selection_menu: None,
 2136            show_git_blame_inline_delay_task: None,
 2137            git_blame_inline_enabled: full_mode
 2138                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2139            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2140            serialize_dirty_buffers: !is_minimap
 2141                && ProjectSettings::get_global(cx)
 2142                    .session
 2143                    .restore_unsaved_buffers,
 2144            blame: None,
 2145            blame_subscription: None,
 2146            tasks: BTreeMap::default(),
 2147
 2148            breakpoint_store,
 2149            gutter_breakpoint_indicator: (None, None),
 2150            hovered_diff_hunk_row: None,
 2151            _subscriptions: (!is_minimap)
 2152                .then(|| {
 2153                    vec![
 2154                        cx.observe(&buffer, Self::on_buffer_changed),
 2155                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2156                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2157                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2158                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2159                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2160                        cx.observe_window_activation(window, |editor, window, cx| {
 2161                            let active = window.is_window_active();
 2162                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2163                                if active {
 2164                                    blink_manager.enable(cx);
 2165                                } else {
 2166                                    blink_manager.disable(cx);
 2167                                }
 2168                            });
 2169                            if active {
 2170                                editor.show_mouse_cursor(cx);
 2171                            }
 2172                        }),
 2173                    ]
 2174                })
 2175                .unwrap_or_default(),
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206
 2207        if is_minimap {
 2208            return editor;
 2209        }
 2210
 2211        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2212            editor
 2213                ._subscriptions
 2214                .push(cx.observe(breakpoints, |_, _, cx| {
 2215                    cx.notify();
 2216                }));
 2217        }
 2218        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2219        editor._subscriptions.extend(project_subscriptions);
 2220
 2221        editor._subscriptions.push(cx.subscribe_in(
 2222            &cx.entity(),
 2223            window,
 2224            |editor, _, e: &EditorEvent, window, cx| match e {
 2225                EditorEvent::ScrollPositionChanged { local, .. } => {
 2226                    if *local {
 2227                        let new_anchor = editor.scroll_manager.anchor();
 2228                        let snapshot = editor.snapshot(window, cx);
 2229                        editor.update_restoration_data(cx, move |data| {
 2230                            data.scroll_position = (
 2231                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2232                                new_anchor.offset,
 2233                            );
 2234                        });
 2235                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2236                        editor.inline_blame_popover.take();
 2237                    }
 2238                }
 2239                EditorEvent::Edited { .. } => {
 2240                    if !vim_enabled(cx) {
 2241                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2242                        let pop_state = editor
 2243                            .change_list
 2244                            .last()
 2245                            .map(|previous| {
 2246                                previous.len() == selections.len()
 2247                                    && previous.iter().enumerate().all(|(ix, p)| {
 2248                                        p.to_display_point(&map).row()
 2249                                            == selections[ix].head().row()
 2250                                    })
 2251                            })
 2252                            .unwrap_or(false);
 2253                        let new_positions = selections
 2254                            .into_iter()
 2255                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2256                            .collect();
 2257                        editor
 2258                            .change_list
 2259                            .push_to_change_list(pop_state, new_positions);
 2260                    }
 2261                }
 2262                _ => (),
 2263            },
 2264        ));
 2265
 2266        if let Some(dap_store) = editor
 2267            .project
 2268            .as_ref()
 2269            .map(|project| project.read(cx).dap_store())
 2270        {
 2271            let weak_editor = cx.weak_entity();
 2272
 2273            editor
 2274                ._subscriptions
 2275                .push(
 2276                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2277                        let session_entity = cx.entity();
 2278                        weak_editor
 2279                            .update(cx, |editor, cx| {
 2280                                editor._subscriptions.push(
 2281                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2282                                );
 2283                            })
 2284                            .ok();
 2285                    }),
 2286                );
 2287
 2288            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2289                editor
 2290                    ._subscriptions
 2291                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2292            }
 2293        }
 2294
 2295        // skip adding the initial selection to selection history
 2296        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2297        editor.end_selection(window, cx);
 2298        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2299
 2300        editor.scroll_manager.show_scrollbars(window, cx);
 2301        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2302
 2303        if full_mode {
 2304            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2305            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2306
 2307            if editor.git_blame_inline_enabled {
 2308                editor.start_git_blame_inline(false, window, cx);
 2309            }
 2310
 2311            editor.go_to_active_debug_line(window, cx);
 2312
 2313            if let Some(buffer) = buffer.read(cx).as_singleton()
 2314                && let Some(project) = editor.project()
 2315            {
 2316                let handle = project.update(cx, |project, cx| {
 2317                    project.register_buffer_with_language_servers(&buffer, cx)
 2318                });
 2319                editor
 2320                    .registered_buffers
 2321                    .insert(buffer.read(cx).remote_id(), handle);
 2322            }
 2323
 2324            editor.minimap =
 2325                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2326            editor.colors = Some(LspColorData::new(cx));
 2327            editor.update_lsp_data(false, None, window, cx);
 2328        }
 2329
 2330        if editor.mode.is_full() {
 2331            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2332        }
 2333
 2334        editor
 2335    }
 2336
 2337    pub fn deploy_mouse_context_menu(
 2338        &mut self,
 2339        position: gpui::Point<Pixels>,
 2340        context_menu: Entity<ContextMenu>,
 2341        window: &mut Window,
 2342        cx: &mut Context<Self>,
 2343    ) {
 2344        self.mouse_context_menu = Some(MouseContextMenu::new(
 2345            self,
 2346            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2347            context_menu,
 2348            window,
 2349            cx,
 2350        ));
 2351    }
 2352
 2353    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2354        self.mouse_context_menu
 2355            .as_ref()
 2356            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2357    }
 2358
 2359    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2360        if self
 2361            .selections
 2362            .pending
 2363            .as_ref()
 2364            .is_some_and(|pending_selection| {
 2365                let snapshot = self.buffer().read(cx).snapshot(cx);
 2366                pending_selection
 2367                    .selection
 2368                    .range()
 2369                    .includes(range, &snapshot)
 2370            })
 2371        {
 2372            return true;
 2373        }
 2374
 2375        self.selections
 2376            .disjoint_in_range::<usize>(range.clone(), cx)
 2377            .into_iter()
 2378            .any(|selection| {
 2379                // This is needed to cover a corner case, if we just check for an existing
 2380                // selection in the fold range, having a cursor at the start of the fold
 2381                // marks it as selected. Non-empty selections don't cause this.
 2382                let length = selection.end - selection.start;
 2383                length > 0
 2384            })
 2385    }
 2386
 2387    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2388        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2389    }
 2390
 2391    fn key_context_internal(
 2392        &self,
 2393        has_active_edit_prediction: bool,
 2394        window: &Window,
 2395        cx: &App,
 2396    ) -> KeyContext {
 2397        let mut key_context = KeyContext::new_with_defaults();
 2398        key_context.add("Editor");
 2399        let mode = match self.mode {
 2400            EditorMode::SingleLine => "single_line",
 2401            EditorMode::AutoHeight { .. } => "auto_height",
 2402            EditorMode::Minimap { .. } => "minimap",
 2403            EditorMode::Full { .. } => "full",
 2404        };
 2405
 2406        if EditorSettings::jupyter_enabled(cx) {
 2407            key_context.add("jupyter");
 2408        }
 2409
 2410        key_context.set("mode", mode);
 2411        if self.pending_rename.is_some() {
 2412            key_context.add("renaming");
 2413        }
 2414
 2415        match self.context_menu.borrow().as_ref() {
 2416            Some(CodeContextMenu::Completions(menu)) => {
 2417                if menu.visible() {
 2418                    key_context.add("menu");
 2419                    key_context.add("showing_completions");
 2420                }
 2421            }
 2422            Some(CodeContextMenu::CodeActions(menu)) => {
 2423                if menu.visible() {
 2424                    key_context.add("menu");
 2425                    key_context.add("showing_code_actions")
 2426                }
 2427            }
 2428            None => {}
 2429        }
 2430
 2431        if self.signature_help_state.has_multiple_signatures() {
 2432            key_context.add("showing_signature_help");
 2433        }
 2434
 2435        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2436        if !self.focus_handle(cx).contains_focused(window, cx)
 2437            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2438        {
 2439            for addon in self.addons.values() {
 2440                addon.extend_key_context(&mut key_context, cx)
 2441            }
 2442        }
 2443
 2444        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2445            if let Some(extension) = singleton_buffer
 2446                .read(cx)
 2447                .file()
 2448                .and_then(|file| file.path().extension()?.to_str())
 2449            {
 2450                key_context.set("extension", extension.to_string());
 2451            }
 2452        } else {
 2453            key_context.add("multibuffer");
 2454        }
 2455
 2456        if has_active_edit_prediction {
 2457            if self.edit_prediction_in_conflict() {
 2458                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2459            } else {
 2460                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2461                key_context.add("copilot_suggestion");
 2462            }
 2463        }
 2464
 2465        if self.selection_mark_mode {
 2466            key_context.add("selection_mode");
 2467        }
 2468
 2469        key_context
 2470    }
 2471
 2472    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2473        if self.mouse_cursor_hidden {
 2474            self.mouse_cursor_hidden = false;
 2475            cx.notify();
 2476        }
 2477    }
 2478
 2479    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2480        let hide_mouse_cursor = match origin {
 2481            HideMouseCursorOrigin::TypingAction => {
 2482                matches!(
 2483                    self.hide_mouse_mode,
 2484                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2485                )
 2486            }
 2487            HideMouseCursorOrigin::MovementAction => {
 2488                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2489            }
 2490        };
 2491        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2492            self.mouse_cursor_hidden = hide_mouse_cursor;
 2493            cx.notify();
 2494        }
 2495    }
 2496
 2497    pub fn edit_prediction_in_conflict(&self) -> bool {
 2498        if !self.show_edit_predictions_in_menu() {
 2499            return false;
 2500        }
 2501
 2502        let showing_completions = self
 2503            .context_menu
 2504            .borrow()
 2505            .as_ref()
 2506            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2507
 2508        showing_completions
 2509            || self.edit_prediction_requires_modifier()
 2510            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2511            // bindings to insert tab characters.
 2512            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2513    }
 2514
 2515    pub fn accept_edit_prediction_keybind(
 2516        &self,
 2517        accept_partial: bool,
 2518        window: &Window,
 2519        cx: &App,
 2520    ) -> AcceptEditPredictionBinding {
 2521        let key_context = self.key_context_internal(true, window, cx);
 2522        let in_conflict = self.edit_prediction_in_conflict();
 2523
 2524        let bindings = if accept_partial {
 2525            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2526        } else {
 2527            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2528        };
 2529
 2530        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2531        // just the first one.
 2532        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2533            !in_conflict
 2534                || binding
 2535                    .keystrokes()
 2536                    .first()
 2537                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2538        }))
 2539    }
 2540
 2541    pub fn new_file(
 2542        workspace: &mut Workspace,
 2543        _: &workspace::NewFile,
 2544        window: &mut Window,
 2545        cx: &mut Context<Workspace>,
 2546    ) {
 2547        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2548            "Failed to create buffer",
 2549            window,
 2550            cx,
 2551            |e, _, _| match e.error_code() {
 2552                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2553                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2554                e.error_tag("required").unwrap_or("the latest version")
 2555            )),
 2556                _ => None,
 2557            },
 2558        );
 2559    }
 2560
 2561    pub fn new_in_workspace(
 2562        workspace: &mut Workspace,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) -> Task<Result<Entity<Editor>>> {
 2566        let project = workspace.project().clone();
 2567        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2568
 2569        cx.spawn_in(window, async move |workspace, cx| {
 2570            let buffer = create.await?;
 2571            workspace.update_in(cx, |workspace, window, cx| {
 2572                let editor =
 2573                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2574                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2575                editor
 2576            })
 2577        })
 2578    }
 2579
 2580    fn new_file_vertical(
 2581        workspace: &mut Workspace,
 2582        _: &workspace::NewFileSplitVertical,
 2583        window: &mut Window,
 2584        cx: &mut Context<Workspace>,
 2585    ) {
 2586        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2587    }
 2588
 2589    fn new_file_horizontal(
 2590        workspace: &mut Workspace,
 2591        _: &workspace::NewFileSplitHorizontal,
 2592        window: &mut Window,
 2593        cx: &mut Context<Workspace>,
 2594    ) {
 2595        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2596    }
 2597
 2598    fn new_file_in_direction(
 2599        workspace: &mut Workspace,
 2600        direction: SplitDirection,
 2601        window: &mut Window,
 2602        cx: &mut Context<Workspace>,
 2603    ) {
 2604        let project = workspace.project().clone();
 2605        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2606
 2607        cx.spawn_in(window, async move |workspace, cx| {
 2608            let buffer = create.await?;
 2609            workspace.update_in(cx, move |workspace, window, cx| {
 2610                workspace.split_item(
 2611                    direction,
 2612                    Box::new(
 2613                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2614                    ),
 2615                    window,
 2616                    cx,
 2617                )
 2618            })?;
 2619            anyhow::Ok(())
 2620        })
 2621        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2622            match e.error_code() {
 2623                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2624                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2625                e.error_tag("required").unwrap_or("the latest version")
 2626            )),
 2627                _ => None,
 2628            }
 2629        });
 2630    }
 2631
 2632    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2633        self.leader_id
 2634    }
 2635
 2636    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2637        &self.buffer
 2638    }
 2639
 2640    pub fn project(&self) -> Option<&Entity<Project>> {
 2641        self.project.as_ref()
 2642    }
 2643
 2644    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2645        self.workspace.as_ref()?.0.upgrade()
 2646    }
 2647
 2648    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2649        self.buffer().read(cx).title(cx)
 2650    }
 2651
 2652    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2653        let git_blame_gutter_max_author_length = self
 2654            .render_git_blame_gutter(cx)
 2655            .then(|| {
 2656                if let Some(blame) = self.blame.as_ref() {
 2657                    let max_author_length =
 2658                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2659                    Some(max_author_length)
 2660                } else {
 2661                    None
 2662                }
 2663            })
 2664            .flatten();
 2665
 2666        EditorSnapshot {
 2667            mode: self.mode.clone(),
 2668            show_gutter: self.show_gutter,
 2669            show_line_numbers: self.show_line_numbers,
 2670            show_git_diff_gutter: self.show_git_diff_gutter,
 2671            show_code_actions: self.show_code_actions,
 2672            show_runnables: self.show_runnables,
 2673            show_breakpoints: self.show_breakpoints,
 2674            git_blame_gutter_max_author_length,
 2675            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2676            scroll_anchor: self.scroll_manager.anchor(),
 2677            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2678            placeholder_text: self.placeholder_text.clone(),
 2679            is_focused: self.focus_handle.is_focused(window),
 2680            current_line_highlight: self
 2681                .current_line_highlight
 2682                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2683            gutter_hovered: self.gutter_hovered,
 2684        }
 2685    }
 2686
 2687    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2688        self.buffer.read(cx).language_at(point, cx)
 2689    }
 2690
 2691    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2692        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2693    }
 2694
 2695    pub fn active_excerpt(
 2696        &self,
 2697        cx: &App,
 2698    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2699        self.buffer
 2700            .read(cx)
 2701            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2702    }
 2703
 2704    pub fn mode(&self) -> &EditorMode {
 2705        &self.mode
 2706    }
 2707
 2708    pub fn set_mode(&mut self, mode: EditorMode) {
 2709        self.mode = mode;
 2710    }
 2711
 2712    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2713        self.collaboration_hub.as_deref()
 2714    }
 2715
 2716    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2717        self.collaboration_hub = Some(hub);
 2718    }
 2719
 2720    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2721        self.in_project_search = in_project_search;
 2722    }
 2723
 2724    pub fn set_custom_context_menu(
 2725        &mut self,
 2726        f: impl 'static
 2727        + Fn(
 2728            &mut Self,
 2729            DisplayPoint,
 2730            &mut Window,
 2731            &mut Context<Self>,
 2732        ) -> Option<Entity<ui::ContextMenu>>,
 2733    ) {
 2734        self.custom_context_menu = Some(Box::new(f))
 2735    }
 2736
 2737    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2738        self.completion_provider = provider;
 2739    }
 2740
 2741    #[cfg(any(test, feature = "test-support"))]
 2742    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2743        self.completion_provider.clone()
 2744    }
 2745
 2746    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2747        self.semantics_provider.clone()
 2748    }
 2749
 2750    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2751        self.semantics_provider = provider;
 2752    }
 2753
 2754    pub fn set_edit_prediction_provider<T>(
 2755        &mut self,
 2756        provider: Option<Entity<T>>,
 2757        window: &mut Window,
 2758        cx: &mut Context<Self>,
 2759    ) where
 2760        T: EditPredictionProvider,
 2761    {
 2762        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2763            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2764                if this.focus_handle.is_focused(window) {
 2765                    this.update_visible_edit_prediction(window, cx);
 2766                }
 2767            }),
 2768            provider: Arc::new(provider),
 2769        });
 2770        self.update_edit_prediction_settings(cx);
 2771        self.refresh_edit_prediction(false, false, window, cx);
 2772    }
 2773
 2774    pub fn placeholder_text(&self) -> Option<&str> {
 2775        self.placeholder_text.as_deref()
 2776    }
 2777
 2778    pub fn set_placeholder_text(
 2779        &mut self,
 2780        placeholder_text: impl Into<Arc<str>>,
 2781        cx: &mut Context<Self>,
 2782    ) {
 2783        let placeholder_text = Some(placeholder_text.into());
 2784        if self.placeholder_text != placeholder_text {
 2785            self.placeholder_text = placeholder_text;
 2786            cx.notify();
 2787        }
 2788    }
 2789
 2790    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2791        self.cursor_shape = cursor_shape;
 2792
 2793        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2794        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2795
 2796        cx.notify();
 2797    }
 2798
 2799    pub fn set_current_line_highlight(
 2800        &mut self,
 2801        current_line_highlight: Option<CurrentLineHighlight>,
 2802    ) {
 2803        self.current_line_highlight = current_line_highlight;
 2804    }
 2805
 2806    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2807        self.collapse_matches = collapse_matches;
 2808    }
 2809
 2810    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2811        let buffers = self.buffer.read(cx).all_buffers();
 2812        let Some(project) = self.project.as_ref() else {
 2813            return;
 2814        };
 2815        project.update(cx, |project, cx| {
 2816            for buffer in buffers {
 2817                self.registered_buffers
 2818                    .entry(buffer.read(cx).remote_id())
 2819                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2820            }
 2821        })
 2822    }
 2823
 2824    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2825        if self.collapse_matches {
 2826            return range.start..range.start;
 2827        }
 2828        range.clone()
 2829    }
 2830
 2831    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2832        if self.display_map.read(cx).clip_at_line_ends != clip {
 2833            self.display_map
 2834                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2835        }
 2836    }
 2837
 2838    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2839        self.input_enabled = input_enabled;
 2840    }
 2841
 2842    pub fn set_edit_predictions_hidden_for_vim_mode(
 2843        &mut self,
 2844        hidden: bool,
 2845        window: &mut Window,
 2846        cx: &mut Context<Self>,
 2847    ) {
 2848        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2849            self.edit_predictions_hidden_for_vim_mode = hidden;
 2850            if hidden {
 2851                self.update_visible_edit_prediction(window, cx);
 2852            } else {
 2853                self.refresh_edit_prediction(true, false, window, cx);
 2854            }
 2855        }
 2856    }
 2857
 2858    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2859        self.menu_edit_predictions_policy = value;
 2860    }
 2861
 2862    pub fn set_autoindent(&mut self, autoindent: bool) {
 2863        if autoindent {
 2864            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2865        } else {
 2866            self.autoindent_mode = None;
 2867        }
 2868    }
 2869
 2870    pub fn read_only(&self, cx: &App) -> bool {
 2871        self.read_only || self.buffer.read(cx).read_only()
 2872    }
 2873
 2874    pub fn set_read_only(&mut self, read_only: bool) {
 2875        self.read_only = read_only;
 2876    }
 2877
 2878    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2879        self.use_autoclose = autoclose;
 2880    }
 2881
 2882    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2883        self.use_auto_surround = auto_surround;
 2884    }
 2885
 2886    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2887        self.auto_replace_emoji_shortcode = auto_replace;
 2888    }
 2889
 2890    pub fn toggle_edit_predictions(
 2891        &mut self,
 2892        _: &ToggleEditPrediction,
 2893        window: &mut Window,
 2894        cx: &mut Context<Self>,
 2895    ) {
 2896        if self.show_edit_predictions_override.is_some() {
 2897            self.set_show_edit_predictions(None, window, cx);
 2898        } else {
 2899            let show_edit_predictions = !self.edit_predictions_enabled();
 2900            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2901        }
 2902    }
 2903
 2904    pub fn set_show_edit_predictions(
 2905        &mut self,
 2906        show_edit_predictions: Option<bool>,
 2907        window: &mut Window,
 2908        cx: &mut Context<Self>,
 2909    ) {
 2910        self.show_edit_predictions_override = show_edit_predictions;
 2911        self.update_edit_prediction_settings(cx);
 2912
 2913        if let Some(false) = show_edit_predictions {
 2914            self.discard_edit_prediction(false, cx);
 2915        } else {
 2916            self.refresh_edit_prediction(false, true, window, cx);
 2917        }
 2918    }
 2919
 2920    fn edit_predictions_disabled_in_scope(
 2921        &self,
 2922        buffer: &Entity<Buffer>,
 2923        buffer_position: language::Anchor,
 2924        cx: &App,
 2925    ) -> bool {
 2926        let snapshot = buffer.read(cx).snapshot();
 2927        let settings = snapshot.settings_at(buffer_position, cx);
 2928
 2929        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2930            return false;
 2931        };
 2932
 2933        scope.override_name().is_some_and(|scope_name| {
 2934            settings
 2935                .edit_predictions_disabled_in
 2936                .iter()
 2937                .any(|s| s == scope_name)
 2938        })
 2939    }
 2940
 2941    pub fn set_use_modal_editing(&mut self, to: bool) {
 2942        self.use_modal_editing = to;
 2943    }
 2944
 2945    pub fn use_modal_editing(&self) -> bool {
 2946        self.use_modal_editing
 2947    }
 2948
 2949    fn selections_did_change(
 2950        &mut self,
 2951        local: bool,
 2952        old_cursor_position: &Anchor,
 2953        effects: SelectionEffects,
 2954        window: &mut Window,
 2955        cx: &mut Context<Self>,
 2956    ) {
 2957        window.invalidate_character_coordinates();
 2958
 2959        // Copy selections to primary selection buffer
 2960        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2961        if local {
 2962            let selections = self.selections.all::<usize>(cx);
 2963            let buffer_handle = self.buffer.read(cx).read(cx);
 2964
 2965            let mut text = String::new();
 2966            for (index, selection) in selections.iter().enumerate() {
 2967                let text_for_selection = buffer_handle
 2968                    .text_for_range(selection.start..selection.end)
 2969                    .collect::<String>();
 2970
 2971                text.push_str(&text_for_selection);
 2972                if index != selections.len() - 1 {
 2973                    text.push('\n');
 2974                }
 2975            }
 2976
 2977            if !text.is_empty() {
 2978                cx.write_to_primary(ClipboardItem::new_string(text));
 2979            }
 2980        }
 2981
 2982        let selection_anchors = self.selections.disjoint_anchors();
 2983
 2984        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2985            self.buffer.update(cx, |buffer, cx| {
 2986                buffer.set_active_selections(
 2987                    &selection_anchors,
 2988                    self.selections.line_mode,
 2989                    self.cursor_shape,
 2990                    cx,
 2991                )
 2992            });
 2993        }
 2994        let display_map = self
 2995            .display_map
 2996            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2997        let buffer = &display_map.buffer_snapshot;
 2998        if self.selections.count() == 1 {
 2999            self.add_selections_state = None;
 3000        }
 3001        self.select_next_state = None;
 3002        self.select_prev_state = None;
 3003        self.select_syntax_node_history.try_clear();
 3004        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3005        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3006        self.take_rename(false, window, cx);
 3007
 3008        let newest_selection = self.selections.newest_anchor();
 3009        let new_cursor_position = newest_selection.head();
 3010        let selection_start = newest_selection.start;
 3011
 3012        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3013            self.push_to_nav_history(
 3014                *old_cursor_position,
 3015                Some(new_cursor_position.to_point(buffer)),
 3016                false,
 3017                effects.nav_history == Some(true),
 3018                cx,
 3019            );
 3020        }
 3021
 3022        if local {
 3023            if let Some(buffer_id) = new_cursor_position.buffer_id
 3024                && !self.registered_buffers.contains_key(&buffer_id)
 3025                && let Some(project) = self.project.as_ref()
 3026            {
 3027                project.update(cx, |project, cx| {
 3028                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3029                        return;
 3030                    };
 3031                    self.registered_buffers.insert(
 3032                        buffer_id,
 3033                        project.register_buffer_with_language_servers(&buffer, cx),
 3034                    );
 3035                })
 3036            }
 3037
 3038            let mut context_menu = self.context_menu.borrow_mut();
 3039            let completion_menu = match context_menu.as_ref() {
 3040                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3041                Some(CodeContextMenu::CodeActions(_)) => {
 3042                    *context_menu = None;
 3043                    None
 3044                }
 3045                None => None,
 3046            };
 3047            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3048            drop(context_menu);
 3049
 3050            if effects.completions
 3051                && let Some(completion_position) = completion_position
 3052            {
 3053                let start_offset = selection_start.to_offset(buffer);
 3054                let position_matches = start_offset == completion_position.to_offset(buffer);
 3055                let continue_showing = if position_matches {
 3056                    if self.snippet_stack.is_empty() {
 3057                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3058                    } else {
 3059                        // Snippet choices can be shown even when the cursor is in whitespace.
 3060                        // Dismissing the menu with actions like backspace is handled by
 3061                        // invalidation regions.
 3062                        true
 3063                    }
 3064                } else {
 3065                    false
 3066                };
 3067
 3068                if continue_showing {
 3069                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3070                } else {
 3071                    self.hide_context_menu(window, cx);
 3072                }
 3073            }
 3074
 3075            hide_hover(self, cx);
 3076
 3077            if old_cursor_position.to_display_point(&display_map).row()
 3078                != new_cursor_position.to_display_point(&display_map).row()
 3079            {
 3080                self.available_code_actions.take();
 3081            }
 3082            self.refresh_code_actions(window, cx);
 3083            self.refresh_document_highlights(cx);
 3084            self.refresh_selected_text_highlights(false, window, cx);
 3085            refresh_matching_bracket_highlights(self, window, cx);
 3086            self.update_visible_edit_prediction(window, cx);
 3087            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3088            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3089            self.inline_blame_popover.take();
 3090            if self.git_blame_inline_enabled {
 3091                self.start_inline_blame_timer(window, cx);
 3092            }
 3093        }
 3094
 3095        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3096        cx.emit(EditorEvent::SelectionsChanged { local });
 3097
 3098        let selections = &self.selections.disjoint;
 3099        if selections.len() == 1 {
 3100            cx.emit(SearchEvent::ActiveMatchChanged)
 3101        }
 3102        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3103            let inmemory_selections = selections
 3104                .iter()
 3105                .map(|s| {
 3106                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3107                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3108                })
 3109                .collect();
 3110            self.update_restoration_data(cx, |data| {
 3111                data.selections = inmemory_selections;
 3112            });
 3113
 3114            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3115                && let Some(workspace_id) =
 3116                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3117            {
 3118                let snapshot = self.buffer().read(cx).snapshot(cx);
 3119                let selections = selections.clone();
 3120                let background_executor = cx.background_executor().clone();
 3121                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3122                self.serialize_selections = cx.background_spawn(async move {
 3123                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3124                            let db_selections = selections
 3125                                .iter()
 3126                                .map(|selection| {
 3127                                    (
 3128                                        selection.start.to_offset(&snapshot),
 3129                                        selection.end.to_offset(&snapshot),
 3130                                    )
 3131                                })
 3132                                .collect();
 3133
 3134                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3135                                .await
 3136                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3137                                .log_err();
 3138                        });
 3139            }
 3140        }
 3141
 3142        cx.notify();
 3143    }
 3144
 3145    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3146        use text::ToOffset as _;
 3147        use text::ToPoint as _;
 3148
 3149        if self.mode.is_minimap()
 3150            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3151        {
 3152            return;
 3153        }
 3154
 3155        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3156            return;
 3157        };
 3158
 3159        let snapshot = singleton.read(cx).snapshot();
 3160        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3161            let display_snapshot = display_map.snapshot(cx);
 3162
 3163            display_snapshot
 3164                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3165                .map(|fold| {
 3166                    fold.range.start.text_anchor.to_point(&snapshot)
 3167                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3168                })
 3169                .collect()
 3170        });
 3171        self.update_restoration_data(cx, |data| {
 3172            data.folds = inmemory_folds;
 3173        });
 3174
 3175        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3176            return;
 3177        };
 3178        let background_executor = cx.background_executor().clone();
 3179        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3180        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3181            display_map
 3182                .snapshot(cx)
 3183                .folds_in_range(0..snapshot.len())
 3184                .map(|fold| {
 3185                    (
 3186                        fold.range.start.text_anchor.to_offset(&snapshot),
 3187                        fold.range.end.text_anchor.to_offset(&snapshot),
 3188                    )
 3189                })
 3190                .collect()
 3191        });
 3192        self.serialize_folds = cx.background_spawn(async move {
 3193            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3194            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3195                .await
 3196                .with_context(|| {
 3197                    format!(
 3198                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3199                    )
 3200                })
 3201                .log_err();
 3202        });
 3203    }
 3204
 3205    pub fn sync_selections(
 3206        &mut self,
 3207        other: Entity<Editor>,
 3208        cx: &mut Context<Self>,
 3209    ) -> gpui::Subscription {
 3210        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3211        self.selections.change_with(cx, |selections| {
 3212            selections.select_anchors(other_selections);
 3213        });
 3214
 3215        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3216            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3217                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3218                if other_selections.is_empty() {
 3219                    return;
 3220                }
 3221                this.selections.change_with(cx, |selections| {
 3222                    selections.select_anchors(other_selections);
 3223                });
 3224            }
 3225        });
 3226
 3227        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3228            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3229                let these_selections = this.selections.disjoint.to_vec();
 3230                if these_selections.is_empty() {
 3231                    return;
 3232                }
 3233                other.update(cx, |other_editor, cx| {
 3234                    other_editor.selections.change_with(cx, |selections| {
 3235                        selections.select_anchors(these_selections);
 3236                    })
 3237                });
 3238            }
 3239        });
 3240
 3241        Subscription::join(other_subscription, this_subscription)
 3242    }
 3243
 3244    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3245    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3246    /// effects of selection change occur at the end of the transaction.
 3247    pub fn change_selections<R>(
 3248        &mut self,
 3249        effects: SelectionEffects,
 3250        window: &mut Window,
 3251        cx: &mut Context<Self>,
 3252        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3253    ) -> R {
 3254        if let Some(state) = &mut self.deferred_selection_effects_state {
 3255            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3256            state.effects.completions = effects.completions;
 3257            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3258            let (changed, result) = self.selections.change_with(cx, change);
 3259            state.changed |= changed;
 3260            return result;
 3261        }
 3262        let mut state = DeferredSelectionEffectsState {
 3263            changed: false,
 3264            effects,
 3265            old_cursor_position: self.selections.newest_anchor().head(),
 3266            history_entry: SelectionHistoryEntry {
 3267                selections: self.selections.disjoint_anchors(),
 3268                select_next_state: self.select_next_state.clone(),
 3269                select_prev_state: self.select_prev_state.clone(),
 3270                add_selections_state: self.add_selections_state.clone(),
 3271            },
 3272        };
 3273        let (changed, result) = self.selections.change_with(cx, change);
 3274        state.changed = state.changed || changed;
 3275        if self.defer_selection_effects {
 3276            self.deferred_selection_effects_state = Some(state);
 3277        } else {
 3278            self.apply_selection_effects(state, window, cx);
 3279        }
 3280        result
 3281    }
 3282
 3283    /// Defers the effects of selection change, so that the effects of multiple calls to
 3284    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3285    /// to selection history and the state of popovers based on selection position aren't
 3286    /// erroneously updated.
 3287    pub fn with_selection_effects_deferred<R>(
 3288        &mut self,
 3289        window: &mut Window,
 3290        cx: &mut Context<Self>,
 3291        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3292    ) -> R {
 3293        let already_deferred = self.defer_selection_effects;
 3294        self.defer_selection_effects = true;
 3295        let result = update(self, window, cx);
 3296        if !already_deferred {
 3297            self.defer_selection_effects = false;
 3298            if let Some(state) = self.deferred_selection_effects_state.take() {
 3299                self.apply_selection_effects(state, window, cx);
 3300            }
 3301        }
 3302        result
 3303    }
 3304
 3305    fn apply_selection_effects(
 3306        &mut self,
 3307        state: DeferredSelectionEffectsState,
 3308        window: &mut Window,
 3309        cx: &mut Context<Self>,
 3310    ) {
 3311        if state.changed {
 3312            self.selection_history.push(state.history_entry);
 3313
 3314            if let Some(autoscroll) = state.effects.scroll {
 3315                self.request_autoscroll(autoscroll, cx);
 3316            }
 3317
 3318            let old_cursor_position = &state.old_cursor_position;
 3319
 3320            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3321
 3322            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3323                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3324            }
 3325        }
 3326    }
 3327
 3328    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3329    where
 3330        I: IntoIterator<Item = (Range<S>, T)>,
 3331        S: ToOffset,
 3332        T: Into<Arc<str>>,
 3333    {
 3334        if self.read_only(cx) {
 3335            return;
 3336        }
 3337
 3338        self.buffer
 3339            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3340    }
 3341
 3342    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3343    where
 3344        I: IntoIterator<Item = (Range<S>, T)>,
 3345        S: ToOffset,
 3346        T: Into<Arc<str>>,
 3347    {
 3348        if self.read_only(cx) {
 3349            return;
 3350        }
 3351
 3352        self.buffer.update(cx, |buffer, cx| {
 3353            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3354        });
 3355    }
 3356
 3357    pub fn edit_with_block_indent<I, S, T>(
 3358        &mut self,
 3359        edits: I,
 3360        original_indent_columns: Vec<Option<u32>>,
 3361        cx: &mut Context<Self>,
 3362    ) where
 3363        I: IntoIterator<Item = (Range<S>, T)>,
 3364        S: ToOffset,
 3365        T: Into<Arc<str>>,
 3366    {
 3367        if self.read_only(cx) {
 3368            return;
 3369        }
 3370
 3371        self.buffer.update(cx, |buffer, cx| {
 3372            buffer.edit(
 3373                edits,
 3374                Some(AutoindentMode::Block {
 3375                    original_indent_columns,
 3376                }),
 3377                cx,
 3378            )
 3379        });
 3380    }
 3381
 3382    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3383        self.hide_context_menu(window, cx);
 3384
 3385        match phase {
 3386            SelectPhase::Begin {
 3387                position,
 3388                add,
 3389                click_count,
 3390            } => self.begin_selection(position, add, click_count, window, cx),
 3391            SelectPhase::BeginColumnar {
 3392                position,
 3393                goal_column,
 3394                reset,
 3395                mode,
 3396            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3397            SelectPhase::Extend {
 3398                position,
 3399                click_count,
 3400            } => self.extend_selection(position, click_count, window, cx),
 3401            SelectPhase::Update {
 3402                position,
 3403                goal_column,
 3404                scroll_delta,
 3405            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3406            SelectPhase::End => self.end_selection(window, cx),
 3407        }
 3408    }
 3409
 3410    fn extend_selection(
 3411        &mut self,
 3412        position: DisplayPoint,
 3413        click_count: usize,
 3414        window: &mut Window,
 3415        cx: &mut Context<Self>,
 3416    ) {
 3417        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3418        let tail = self.selections.newest::<usize>(cx).tail();
 3419        self.begin_selection(position, false, click_count, window, cx);
 3420
 3421        let position = position.to_offset(&display_map, Bias::Left);
 3422        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3423
 3424        let mut pending_selection = self
 3425            .selections
 3426            .pending_anchor()
 3427            .expect("extend_selection not called with pending selection");
 3428        if position >= tail {
 3429            pending_selection.start = tail_anchor;
 3430        } else {
 3431            pending_selection.end = tail_anchor;
 3432            pending_selection.reversed = true;
 3433        }
 3434
 3435        let mut pending_mode = self.selections.pending_mode().unwrap();
 3436        match &mut pending_mode {
 3437            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3438            _ => {}
 3439        }
 3440
 3441        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3442            SelectionEffects::scroll(Autoscroll::fit())
 3443        } else {
 3444            SelectionEffects::no_scroll()
 3445        };
 3446
 3447        self.change_selections(effects, window, cx, |s| {
 3448            s.set_pending(pending_selection, pending_mode)
 3449        });
 3450    }
 3451
 3452    fn begin_selection(
 3453        &mut self,
 3454        position: DisplayPoint,
 3455        add: bool,
 3456        click_count: usize,
 3457        window: &mut Window,
 3458        cx: &mut Context<Self>,
 3459    ) {
 3460        if !self.focus_handle.is_focused(window) {
 3461            self.last_focused_descendant = None;
 3462            window.focus(&self.focus_handle);
 3463        }
 3464
 3465        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3466        let buffer = &display_map.buffer_snapshot;
 3467        let position = display_map.clip_point(position, Bias::Left);
 3468
 3469        let start;
 3470        let end;
 3471        let mode;
 3472        let mut auto_scroll;
 3473        match click_count {
 3474            1 => {
 3475                start = buffer.anchor_before(position.to_point(&display_map));
 3476                end = start;
 3477                mode = SelectMode::Character;
 3478                auto_scroll = true;
 3479            }
 3480            2 => {
 3481                let position = display_map
 3482                    .clip_point(position, Bias::Left)
 3483                    .to_offset(&display_map, Bias::Left);
 3484                let (range, _) = buffer.surrounding_word(position, false);
 3485                start = buffer.anchor_before(range.start);
 3486                end = buffer.anchor_before(range.end);
 3487                mode = SelectMode::Word(start..end);
 3488                auto_scroll = true;
 3489            }
 3490            3 => {
 3491                let position = display_map
 3492                    .clip_point(position, Bias::Left)
 3493                    .to_point(&display_map);
 3494                let line_start = display_map.prev_line_boundary(position).0;
 3495                let next_line_start = buffer.clip_point(
 3496                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3497                    Bias::Left,
 3498                );
 3499                start = buffer.anchor_before(line_start);
 3500                end = buffer.anchor_before(next_line_start);
 3501                mode = SelectMode::Line(start..end);
 3502                auto_scroll = true;
 3503            }
 3504            _ => {
 3505                start = buffer.anchor_before(0);
 3506                end = buffer.anchor_before(buffer.len());
 3507                mode = SelectMode::All;
 3508                auto_scroll = false;
 3509            }
 3510        }
 3511        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3512
 3513        let point_to_delete: Option<usize> = {
 3514            let selected_points: Vec<Selection<Point>> =
 3515                self.selections.disjoint_in_range(start..end, cx);
 3516
 3517            if !add || click_count > 1 {
 3518                None
 3519            } else if !selected_points.is_empty() {
 3520                Some(selected_points[0].id)
 3521            } else {
 3522                let clicked_point_already_selected =
 3523                    self.selections.disjoint.iter().find(|selection| {
 3524                        selection.start.to_point(buffer) == start.to_point(buffer)
 3525                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3526                    });
 3527
 3528                clicked_point_already_selected.map(|selection| selection.id)
 3529            }
 3530        };
 3531
 3532        let selections_count = self.selections.count();
 3533        let effects = if auto_scroll {
 3534            SelectionEffects::default()
 3535        } else {
 3536            SelectionEffects::no_scroll()
 3537        };
 3538
 3539        self.change_selections(effects, window, cx, |s| {
 3540            if let Some(point_to_delete) = point_to_delete {
 3541                s.delete(point_to_delete);
 3542
 3543                if selections_count == 1 {
 3544                    s.set_pending_anchor_range(start..end, mode);
 3545                }
 3546            } else {
 3547                if !add {
 3548                    s.clear_disjoint();
 3549                }
 3550
 3551                s.set_pending_anchor_range(start..end, mode);
 3552            }
 3553        });
 3554    }
 3555
 3556    fn begin_columnar_selection(
 3557        &mut self,
 3558        position: DisplayPoint,
 3559        goal_column: u32,
 3560        reset: bool,
 3561        mode: ColumnarMode,
 3562        window: &mut Window,
 3563        cx: &mut Context<Self>,
 3564    ) {
 3565        if !self.focus_handle.is_focused(window) {
 3566            self.last_focused_descendant = None;
 3567            window.focus(&self.focus_handle);
 3568        }
 3569
 3570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3571
 3572        if reset {
 3573            let pointer_position = display_map
 3574                .buffer_snapshot
 3575                .anchor_before(position.to_point(&display_map));
 3576
 3577            self.change_selections(
 3578                SelectionEffects::scroll(Autoscroll::newest()),
 3579                window,
 3580                cx,
 3581                |s| {
 3582                    s.clear_disjoint();
 3583                    s.set_pending_anchor_range(
 3584                        pointer_position..pointer_position,
 3585                        SelectMode::Character,
 3586                    );
 3587                },
 3588            );
 3589        };
 3590
 3591        let tail = self.selections.newest::<Point>(cx).tail();
 3592        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3593        self.columnar_selection_state = match mode {
 3594            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3595                selection_tail: selection_anchor,
 3596                display_point: if reset {
 3597                    if position.column() != goal_column {
 3598                        Some(DisplayPoint::new(position.row(), goal_column))
 3599                    } else {
 3600                        None
 3601                    }
 3602                } else {
 3603                    None
 3604                },
 3605            }),
 3606            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3607                selection_tail: selection_anchor,
 3608            }),
 3609        };
 3610
 3611        if !reset {
 3612            self.select_columns(position, goal_column, &display_map, window, cx);
 3613        }
 3614    }
 3615
 3616    fn update_selection(
 3617        &mut self,
 3618        position: DisplayPoint,
 3619        goal_column: u32,
 3620        scroll_delta: gpui::Point<f32>,
 3621        window: &mut Window,
 3622        cx: &mut Context<Self>,
 3623    ) {
 3624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3625
 3626        if self.columnar_selection_state.is_some() {
 3627            self.select_columns(position, goal_column, &display_map, window, cx);
 3628        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3629            let buffer = &display_map.buffer_snapshot;
 3630            let head;
 3631            let tail;
 3632            let mode = self.selections.pending_mode().unwrap();
 3633            match &mode {
 3634                SelectMode::Character => {
 3635                    head = position.to_point(&display_map);
 3636                    tail = pending.tail().to_point(buffer);
 3637                }
 3638                SelectMode::Word(original_range) => {
 3639                    let offset = display_map
 3640                        .clip_point(position, Bias::Left)
 3641                        .to_offset(&display_map, Bias::Left);
 3642                    let original_range = original_range.to_offset(buffer);
 3643
 3644                    let head_offset = if buffer.is_inside_word(offset, false)
 3645                        || original_range.contains(&offset)
 3646                    {
 3647                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3648                        if word_range.start < original_range.start {
 3649                            word_range.start
 3650                        } else {
 3651                            word_range.end
 3652                        }
 3653                    } else {
 3654                        offset
 3655                    };
 3656
 3657                    head = head_offset.to_point(buffer);
 3658                    if head_offset <= original_range.start {
 3659                        tail = original_range.end.to_point(buffer);
 3660                    } else {
 3661                        tail = original_range.start.to_point(buffer);
 3662                    }
 3663                }
 3664                SelectMode::Line(original_range) => {
 3665                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3666
 3667                    let position = display_map
 3668                        .clip_point(position, Bias::Left)
 3669                        .to_point(&display_map);
 3670                    let line_start = display_map.prev_line_boundary(position).0;
 3671                    let next_line_start = buffer.clip_point(
 3672                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3673                        Bias::Left,
 3674                    );
 3675
 3676                    if line_start < original_range.start {
 3677                        head = line_start
 3678                    } else {
 3679                        head = next_line_start
 3680                    }
 3681
 3682                    if head <= original_range.start {
 3683                        tail = original_range.end;
 3684                    } else {
 3685                        tail = original_range.start;
 3686                    }
 3687                }
 3688                SelectMode::All => {
 3689                    return;
 3690                }
 3691            };
 3692
 3693            if head < tail {
 3694                pending.start = buffer.anchor_before(head);
 3695                pending.end = buffer.anchor_before(tail);
 3696                pending.reversed = true;
 3697            } else {
 3698                pending.start = buffer.anchor_before(tail);
 3699                pending.end = buffer.anchor_before(head);
 3700                pending.reversed = false;
 3701            }
 3702
 3703            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3704                s.set_pending(pending, mode);
 3705            });
 3706        } else {
 3707            log::error!("update_selection dispatched with no pending selection");
 3708            return;
 3709        }
 3710
 3711        self.apply_scroll_delta(scroll_delta, window, cx);
 3712        cx.notify();
 3713    }
 3714
 3715    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3716        self.columnar_selection_state.take();
 3717        if self.selections.pending_anchor().is_some() {
 3718            let selections = self.selections.all::<usize>(cx);
 3719            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3720                s.select(selections);
 3721                s.clear_pending();
 3722            });
 3723        }
 3724    }
 3725
 3726    fn select_columns(
 3727        &mut self,
 3728        head: DisplayPoint,
 3729        goal_column: u32,
 3730        display_map: &DisplaySnapshot,
 3731        window: &mut Window,
 3732        cx: &mut Context<Self>,
 3733    ) {
 3734        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3735            return;
 3736        };
 3737
 3738        let tail = match columnar_state {
 3739            ColumnarSelectionState::FromMouse {
 3740                selection_tail,
 3741                display_point,
 3742            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3743            ColumnarSelectionState::FromSelection { selection_tail } => {
 3744                selection_tail.to_display_point(display_map)
 3745            }
 3746        };
 3747
 3748        let start_row = cmp::min(tail.row(), head.row());
 3749        let end_row = cmp::max(tail.row(), head.row());
 3750        let start_column = cmp::min(tail.column(), goal_column);
 3751        let end_column = cmp::max(tail.column(), goal_column);
 3752        let reversed = start_column < tail.column();
 3753
 3754        let selection_ranges = (start_row.0..=end_row.0)
 3755            .map(DisplayRow)
 3756            .filter_map(|row| {
 3757                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3758                    || start_column <= display_map.line_len(row))
 3759                    && !display_map.is_block_line(row)
 3760                {
 3761                    let start = display_map
 3762                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3763                        .to_point(display_map);
 3764                    let end = display_map
 3765                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3766                        .to_point(display_map);
 3767                    if reversed {
 3768                        Some(end..start)
 3769                    } else {
 3770                        Some(start..end)
 3771                    }
 3772                } else {
 3773                    None
 3774                }
 3775            })
 3776            .collect::<Vec<_>>();
 3777
 3778        let ranges = match columnar_state {
 3779            ColumnarSelectionState::FromMouse { .. } => {
 3780                let mut non_empty_ranges = selection_ranges
 3781                    .iter()
 3782                    .filter(|selection_range| selection_range.start != selection_range.end)
 3783                    .peekable();
 3784                if non_empty_ranges.peek().is_some() {
 3785                    non_empty_ranges.cloned().collect()
 3786                } else {
 3787                    selection_ranges
 3788                }
 3789            }
 3790            _ => selection_ranges,
 3791        };
 3792
 3793        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3794            s.select_ranges(ranges);
 3795        });
 3796        cx.notify();
 3797    }
 3798
 3799    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3800        self.selections
 3801            .all_adjusted(cx)
 3802            .iter()
 3803            .any(|selection| !selection.is_empty())
 3804    }
 3805
 3806    pub fn has_pending_nonempty_selection(&self) -> bool {
 3807        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3808            Some(Selection { start, end, .. }) => start != end,
 3809            None => false,
 3810        };
 3811
 3812        pending_nonempty_selection
 3813            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3814    }
 3815
 3816    pub fn has_pending_selection(&self) -> bool {
 3817        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3818    }
 3819
 3820    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3821        self.selection_mark_mode = false;
 3822        self.selection_drag_state = SelectionDragState::None;
 3823
 3824        if self.clear_expanded_diff_hunks(cx) {
 3825            cx.notify();
 3826            return;
 3827        }
 3828        if self.dismiss_menus_and_popups(true, window, cx) {
 3829            return;
 3830        }
 3831
 3832        if self.mode.is_full()
 3833            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3834        {
 3835            return;
 3836        }
 3837
 3838        cx.propagate();
 3839    }
 3840
 3841    pub fn dismiss_menus_and_popups(
 3842        &mut self,
 3843        is_user_requested: bool,
 3844        window: &mut Window,
 3845        cx: &mut Context<Self>,
 3846    ) -> bool {
 3847        if self.take_rename(false, window, cx).is_some() {
 3848            return true;
 3849        }
 3850
 3851        if hide_hover(self, cx) {
 3852            return true;
 3853        }
 3854
 3855        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3856            return true;
 3857        }
 3858
 3859        if self.hide_context_menu(window, cx).is_some() {
 3860            return true;
 3861        }
 3862
 3863        if self.mouse_context_menu.take().is_some() {
 3864            return true;
 3865        }
 3866
 3867        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3868            return true;
 3869        }
 3870
 3871        if self.snippet_stack.pop().is_some() {
 3872            return true;
 3873        }
 3874
 3875        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3876            self.dismiss_diagnostics(cx);
 3877            return true;
 3878        }
 3879
 3880        false
 3881    }
 3882
 3883    fn linked_editing_ranges_for(
 3884        &self,
 3885        selection: Range<text::Anchor>,
 3886        cx: &App,
 3887    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3888        if self.linked_edit_ranges.is_empty() {
 3889            return None;
 3890        }
 3891        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3892            selection.end.buffer_id.and_then(|end_buffer_id| {
 3893                if selection.start.buffer_id != Some(end_buffer_id) {
 3894                    return None;
 3895                }
 3896                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3897                let snapshot = buffer.read(cx).snapshot();
 3898                self.linked_edit_ranges
 3899                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3900                    .map(|ranges| (ranges, snapshot, buffer))
 3901            })?;
 3902        use text::ToOffset as TO;
 3903        // find offset from the start of current range to current cursor position
 3904        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3905
 3906        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3907        let start_difference = start_offset - start_byte_offset;
 3908        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3909        let end_difference = end_offset - start_byte_offset;
 3910        // Current range has associated linked ranges.
 3911        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3912        for range in linked_ranges.iter() {
 3913            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3914            let end_offset = start_offset + end_difference;
 3915            let start_offset = start_offset + start_difference;
 3916            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3917                continue;
 3918            }
 3919            if self.selections.disjoint_anchor_ranges().any(|s| {
 3920                if s.start.buffer_id != selection.start.buffer_id
 3921                    || s.end.buffer_id != selection.end.buffer_id
 3922                {
 3923                    return false;
 3924                }
 3925                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3926                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3927            }) {
 3928                continue;
 3929            }
 3930            let start = buffer_snapshot.anchor_after(start_offset);
 3931            let end = buffer_snapshot.anchor_after(end_offset);
 3932            linked_edits
 3933                .entry(buffer.clone())
 3934                .or_default()
 3935                .push(start..end);
 3936        }
 3937        Some(linked_edits)
 3938    }
 3939
 3940    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3941        let text: Arc<str> = text.into();
 3942
 3943        if self.read_only(cx) {
 3944            return;
 3945        }
 3946
 3947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3948
 3949        let selections = self.selections.all_adjusted(cx);
 3950        let mut bracket_inserted = false;
 3951        let mut edits = Vec::new();
 3952        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3953        let mut new_selections = Vec::with_capacity(selections.len());
 3954        let mut new_autoclose_regions = Vec::new();
 3955        let snapshot = self.buffer.read(cx).read(cx);
 3956        let mut clear_linked_edit_ranges = false;
 3957
 3958        for (selection, autoclose_region) in
 3959            self.selections_with_autoclose_regions(selections, &snapshot)
 3960        {
 3961            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3962                // Determine if the inserted text matches the opening or closing
 3963                // bracket of any of this language's bracket pairs.
 3964                let mut bracket_pair = None;
 3965                let mut is_bracket_pair_start = false;
 3966                let mut is_bracket_pair_end = false;
 3967                if !text.is_empty() {
 3968                    let mut bracket_pair_matching_end = None;
 3969                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3970                    //  and they are removing the character that triggered IME popup.
 3971                    for (pair, enabled) in scope.brackets() {
 3972                        if !pair.close && !pair.surround {
 3973                            continue;
 3974                        }
 3975
 3976                        if enabled && pair.start.ends_with(text.as_ref()) {
 3977                            let prefix_len = pair.start.len() - text.len();
 3978                            let preceding_text_matches_prefix = prefix_len == 0
 3979                                || (selection.start.column >= (prefix_len as u32)
 3980                                    && snapshot.contains_str_at(
 3981                                        Point::new(
 3982                                            selection.start.row,
 3983                                            selection.start.column - (prefix_len as u32),
 3984                                        ),
 3985                                        &pair.start[..prefix_len],
 3986                                    ));
 3987                            if preceding_text_matches_prefix {
 3988                                bracket_pair = Some(pair.clone());
 3989                                is_bracket_pair_start = true;
 3990                                break;
 3991                            }
 3992                        }
 3993                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3994                        {
 3995                            // take first bracket pair matching end, but don't break in case a later bracket
 3996                            // pair matches start
 3997                            bracket_pair_matching_end = Some(pair.clone());
 3998                        }
 3999                    }
 4000                    if let Some(end) = bracket_pair_matching_end
 4001                        && bracket_pair.is_none()
 4002                    {
 4003                        bracket_pair = Some(end);
 4004                        is_bracket_pair_end = true;
 4005                    }
 4006                }
 4007
 4008                if let Some(bracket_pair) = bracket_pair {
 4009                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4010                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4011                    let auto_surround =
 4012                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4013                    if selection.is_empty() {
 4014                        if is_bracket_pair_start {
 4015                            // If the inserted text is a suffix of an opening bracket and the
 4016                            // selection is preceded by the rest of the opening bracket, then
 4017                            // insert the closing bracket.
 4018                            let following_text_allows_autoclose = snapshot
 4019                                .chars_at(selection.start)
 4020                                .next()
 4021                                .is_none_or(|c| scope.should_autoclose_before(c));
 4022
 4023                            let preceding_text_allows_autoclose = selection.start.column == 0
 4024                                || snapshot
 4025                                    .reversed_chars_at(selection.start)
 4026                                    .next()
 4027                                    .is_none_or(|c| {
 4028                                        bracket_pair.start != bracket_pair.end
 4029                                            || !snapshot
 4030                                                .char_classifier_at(selection.start)
 4031                                                .is_word(c)
 4032                                    });
 4033
 4034                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4035                                && bracket_pair.start.len() == 1
 4036                            {
 4037                                let target = bracket_pair.start.chars().next().unwrap();
 4038                                let current_line_count = snapshot
 4039                                    .reversed_chars_at(selection.start)
 4040                                    .take_while(|&c| c != '\n')
 4041                                    .filter(|&c| c == target)
 4042                                    .count();
 4043                                current_line_count % 2 == 1
 4044                            } else {
 4045                                false
 4046                            };
 4047
 4048                            if autoclose
 4049                                && bracket_pair.close
 4050                                && following_text_allows_autoclose
 4051                                && preceding_text_allows_autoclose
 4052                                && !is_closing_quote
 4053                            {
 4054                                let anchor = snapshot.anchor_before(selection.end);
 4055                                new_selections.push((selection.map(|_| anchor), text.len()));
 4056                                new_autoclose_regions.push((
 4057                                    anchor,
 4058                                    text.len(),
 4059                                    selection.id,
 4060                                    bracket_pair.clone(),
 4061                                ));
 4062                                edits.push((
 4063                                    selection.range(),
 4064                                    format!("{}{}", text, bracket_pair.end).into(),
 4065                                ));
 4066                                bracket_inserted = true;
 4067                                continue;
 4068                            }
 4069                        }
 4070
 4071                        if let Some(region) = autoclose_region {
 4072                            // If the selection is followed by an auto-inserted closing bracket,
 4073                            // then don't insert that closing bracket again; just move the selection
 4074                            // past the closing bracket.
 4075                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4076                                && text.as_ref() == region.pair.end.as_str()
 4077                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4078                            if should_skip {
 4079                                let anchor = snapshot.anchor_after(selection.end);
 4080                                new_selections
 4081                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4082                                continue;
 4083                            }
 4084                        }
 4085
 4086                        let always_treat_brackets_as_autoclosed = snapshot
 4087                            .language_settings_at(selection.start, cx)
 4088                            .always_treat_brackets_as_autoclosed;
 4089                        if always_treat_brackets_as_autoclosed
 4090                            && is_bracket_pair_end
 4091                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4092                        {
 4093                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4094                            // and the inserted text is a closing bracket and the selection is followed
 4095                            // by the closing bracket then move the selection past the closing bracket.
 4096                            let anchor = snapshot.anchor_after(selection.end);
 4097                            new_selections.push((selection.map(|_| anchor), text.len()));
 4098                            continue;
 4099                        }
 4100                    }
 4101                    // If an opening bracket is 1 character long and is typed while
 4102                    // text is selected, then surround that text with the bracket pair.
 4103                    else if auto_surround
 4104                        && bracket_pair.surround
 4105                        && is_bracket_pair_start
 4106                        && bracket_pair.start.chars().count() == 1
 4107                    {
 4108                        edits.push((selection.start..selection.start, text.clone()));
 4109                        edits.push((
 4110                            selection.end..selection.end,
 4111                            bracket_pair.end.as_str().into(),
 4112                        ));
 4113                        bracket_inserted = true;
 4114                        new_selections.push((
 4115                            Selection {
 4116                                id: selection.id,
 4117                                start: snapshot.anchor_after(selection.start),
 4118                                end: snapshot.anchor_before(selection.end),
 4119                                reversed: selection.reversed,
 4120                                goal: selection.goal,
 4121                            },
 4122                            0,
 4123                        ));
 4124                        continue;
 4125                    }
 4126                }
 4127            }
 4128
 4129            if self.auto_replace_emoji_shortcode
 4130                && selection.is_empty()
 4131                && text.as_ref().ends_with(':')
 4132                && let Some(possible_emoji_short_code) =
 4133                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4134                && !possible_emoji_short_code.is_empty()
 4135                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4136            {
 4137                let emoji_shortcode_start = Point::new(
 4138                    selection.start.row,
 4139                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4140                );
 4141
 4142                // Remove shortcode from buffer
 4143                edits.push((
 4144                    emoji_shortcode_start..selection.start,
 4145                    "".to_string().into(),
 4146                ));
 4147                new_selections.push((
 4148                    Selection {
 4149                        id: selection.id,
 4150                        start: snapshot.anchor_after(emoji_shortcode_start),
 4151                        end: snapshot.anchor_before(selection.start),
 4152                        reversed: selection.reversed,
 4153                        goal: selection.goal,
 4154                    },
 4155                    0,
 4156                ));
 4157
 4158                // Insert emoji
 4159                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4160                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4161                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4162
 4163                continue;
 4164            }
 4165
 4166            // If not handling any auto-close operation, then just replace the selected
 4167            // text with the given input and move the selection to the end of the
 4168            // newly inserted text.
 4169            let anchor = snapshot.anchor_after(selection.end);
 4170            if !self.linked_edit_ranges.is_empty() {
 4171                let start_anchor = snapshot.anchor_before(selection.start);
 4172
 4173                let is_word_char = text.chars().next().is_none_or(|char| {
 4174                    let classifier = snapshot
 4175                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4176                        .ignore_punctuation(true);
 4177                    classifier.is_word(char)
 4178                });
 4179
 4180                if is_word_char {
 4181                    if let Some(ranges) = self
 4182                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4183                    {
 4184                        for (buffer, edits) in ranges {
 4185                            linked_edits
 4186                                .entry(buffer.clone())
 4187                                .or_default()
 4188                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4189                        }
 4190                    }
 4191                } else {
 4192                    clear_linked_edit_ranges = true;
 4193                }
 4194            }
 4195
 4196            new_selections.push((selection.map(|_| anchor), 0));
 4197            edits.push((selection.start..selection.end, text.clone()));
 4198        }
 4199
 4200        drop(snapshot);
 4201
 4202        self.transact(window, cx, |this, window, cx| {
 4203            if clear_linked_edit_ranges {
 4204                this.linked_edit_ranges.clear();
 4205            }
 4206            let initial_buffer_versions =
 4207                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4208
 4209            this.buffer.update(cx, |buffer, cx| {
 4210                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4211            });
 4212            for (buffer, edits) in linked_edits {
 4213                buffer.update(cx, |buffer, cx| {
 4214                    let snapshot = buffer.snapshot();
 4215                    let edits = edits
 4216                        .into_iter()
 4217                        .map(|(range, text)| {
 4218                            use text::ToPoint as TP;
 4219                            let end_point = TP::to_point(&range.end, &snapshot);
 4220                            let start_point = TP::to_point(&range.start, &snapshot);
 4221                            (start_point..end_point, text)
 4222                        })
 4223                        .sorted_by_key(|(range, _)| range.start);
 4224                    buffer.edit(edits, None, cx);
 4225                })
 4226            }
 4227            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4228            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4229            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4230            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4231                .zip(new_selection_deltas)
 4232                .map(|(selection, delta)| Selection {
 4233                    id: selection.id,
 4234                    start: selection.start + delta,
 4235                    end: selection.end + delta,
 4236                    reversed: selection.reversed,
 4237                    goal: SelectionGoal::None,
 4238                })
 4239                .collect::<Vec<_>>();
 4240
 4241            let mut i = 0;
 4242            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4243                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4244                let start = map.buffer_snapshot.anchor_before(position);
 4245                let end = map.buffer_snapshot.anchor_after(position);
 4246                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4247                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4248                        Ordering::Less => i += 1,
 4249                        Ordering::Greater => break,
 4250                        Ordering::Equal => {
 4251                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4252                                Ordering::Less => i += 1,
 4253                                Ordering::Equal => break,
 4254                                Ordering::Greater => break,
 4255                            }
 4256                        }
 4257                    }
 4258                }
 4259                this.autoclose_regions.insert(
 4260                    i,
 4261                    AutocloseRegion {
 4262                        selection_id,
 4263                        range: start..end,
 4264                        pair,
 4265                    },
 4266                );
 4267            }
 4268
 4269            let had_active_edit_prediction = this.has_active_edit_prediction();
 4270            this.change_selections(
 4271                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4272                window,
 4273                cx,
 4274                |s| s.select(new_selections),
 4275            );
 4276
 4277            if !bracket_inserted
 4278                && let Some(on_type_format_task) =
 4279                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4280            {
 4281                on_type_format_task.detach_and_log_err(cx);
 4282            }
 4283
 4284            let editor_settings = EditorSettings::get_global(cx);
 4285            if bracket_inserted
 4286                && (editor_settings.auto_signature_help
 4287                    || editor_settings.show_signature_help_after_edits)
 4288            {
 4289                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4290            }
 4291
 4292            let trigger_in_words =
 4293                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4294            if this.hard_wrap.is_some() {
 4295                let latest: Range<Point> = this.selections.newest(cx).range();
 4296                if latest.is_empty()
 4297                    && this
 4298                        .buffer()
 4299                        .read(cx)
 4300                        .snapshot(cx)
 4301                        .line_len(MultiBufferRow(latest.start.row))
 4302                        == latest.start.column
 4303                {
 4304                    this.rewrap_impl(
 4305                        RewrapOptions {
 4306                            override_language_settings: true,
 4307                            preserve_existing_whitespace: true,
 4308                        },
 4309                        cx,
 4310                    )
 4311                }
 4312            }
 4313            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4314            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4315            this.refresh_edit_prediction(true, false, window, cx);
 4316            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4317        });
 4318    }
 4319
 4320    fn find_possible_emoji_shortcode_at_position(
 4321        snapshot: &MultiBufferSnapshot,
 4322        position: Point,
 4323    ) -> Option<String> {
 4324        let mut chars = Vec::new();
 4325        let mut found_colon = false;
 4326        for char in snapshot.reversed_chars_at(position).take(100) {
 4327            // Found a possible emoji shortcode in the middle of the buffer
 4328            if found_colon {
 4329                if char.is_whitespace() {
 4330                    chars.reverse();
 4331                    return Some(chars.iter().collect());
 4332                }
 4333                // If the previous character is not a whitespace, we are in the middle of a word
 4334                // and we only want to complete the shortcode if the word is made up of other emojis
 4335                let mut containing_word = String::new();
 4336                for ch in snapshot
 4337                    .reversed_chars_at(position)
 4338                    .skip(chars.len() + 1)
 4339                    .take(100)
 4340                {
 4341                    if ch.is_whitespace() {
 4342                        break;
 4343                    }
 4344                    containing_word.push(ch);
 4345                }
 4346                let containing_word = containing_word.chars().rev().collect::<String>();
 4347                if util::word_consists_of_emojis(containing_word.as_str()) {
 4348                    chars.reverse();
 4349                    return Some(chars.iter().collect());
 4350                }
 4351            }
 4352
 4353            if char.is_whitespace() || !char.is_ascii() {
 4354                return None;
 4355            }
 4356            if char == ':' {
 4357                found_colon = true;
 4358            } else {
 4359                chars.push(char);
 4360            }
 4361        }
 4362        // Found a possible emoji shortcode at the beginning of the buffer
 4363        chars.reverse();
 4364        Some(chars.iter().collect())
 4365    }
 4366
 4367    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4369        self.transact(window, cx, |this, window, cx| {
 4370            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4371                let selections = this.selections.all::<usize>(cx);
 4372                let multi_buffer = this.buffer.read(cx);
 4373                let buffer = multi_buffer.snapshot(cx);
 4374                selections
 4375                    .iter()
 4376                    .map(|selection| {
 4377                        let start_point = selection.start.to_point(&buffer);
 4378                        let mut existing_indent =
 4379                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4380                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4381                        let start = selection.start;
 4382                        let end = selection.end;
 4383                        let selection_is_empty = start == end;
 4384                        let language_scope = buffer.language_scope_at(start);
 4385                        let (
 4386                            comment_delimiter,
 4387                            doc_delimiter,
 4388                            insert_extra_newline,
 4389                            indent_on_newline,
 4390                            indent_on_extra_newline,
 4391                        ) = if let Some(language) = &language_scope {
 4392                            let mut insert_extra_newline =
 4393                                insert_extra_newline_brackets(&buffer, start..end, language)
 4394                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4395
 4396                            // Comment extension on newline is allowed only for cursor selections
 4397                            let comment_delimiter = maybe!({
 4398                                if !selection_is_empty {
 4399                                    return None;
 4400                                }
 4401
 4402                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4403                                    return None;
 4404                                }
 4405
 4406                                let delimiters = language.line_comment_prefixes();
 4407                                let max_len_of_delimiter =
 4408                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4409                                let (snapshot, range) =
 4410                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4411
 4412                                let num_of_whitespaces = snapshot
 4413                                    .chars_for_range(range.clone())
 4414                                    .take_while(|c| c.is_whitespace())
 4415                                    .count();
 4416                                let comment_candidate = snapshot
 4417                                    .chars_for_range(range.clone())
 4418                                    .skip(num_of_whitespaces)
 4419                                    .take(max_len_of_delimiter)
 4420                                    .collect::<String>();
 4421                                let (delimiter, trimmed_len) = delimiters
 4422                                    .iter()
 4423                                    .filter_map(|delimiter| {
 4424                                        let prefix = delimiter.trim_end();
 4425                                        if comment_candidate.starts_with(prefix) {
 4426                                            Some((delimiter, prefix.len()))
 4427                                        } else {
 4428                                            None
 4429                                        }
 4430                                    })
 4431                                    .max_by_key(|(_, len)| *len)?;
 4432
 4433                                if let Some(BlockCommentConfig {
 4434                                    start: block_start, ..
 4435                                }) = language.block_comment()
 4436                                {
 4437                                    let block_start_trimmed = block_start.trim_end();
 4438                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4439                                        let line_content = snapshot
 4440                                            .chars_for_range(range)
 4441                                            .skip(num_of_whitespaces)
 4442                                            .take(block_start_trimmed.len())
 4443                                            .collect::<String>();
 4444
 4445                                        if line_content.starts_with(block_start_trimmed) {
 4446                                            return None;
 4447                                        }
 4448                                    }
 4449                                }
 4450
 4451                                let cursor_is_placed_after_comment_marker =
 4452                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4453                                if cursor_is_placed_after_comment_marker {
 4454                                    Some(delimiter.clone())
 4455                                } else {
 4456                                    None
 4457                                }
 4458                            });
 4459
 4460                            let mut indent_on_newline = IndentSize::spaces(0);
 4461                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4462
 4463                            let doc_delimiter = maybe!({
 4464                                if !selection_is_empty {
 4465                                    return None;
 4466                                }
 4467
 4468                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4469                                    return None;
 4470                                }
 4471
 4472                                let BlockCommentConfig {
 4473                                    start: start_tag,
 4474                                    end: end_tag,
 4475                                    prefix: delimiter,
 4476                                    tab_size: len,
 4477                                } = language.documentation_comment()?;
 4478                                let is_within_block_comment = buffer
 4479                                    .language_scope_at(start_point)
 4480                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4481                                if !is_within_block_comment {
 4482                                    return None;
 4483                                }
 4484
 4485                                let (snapshot, range) =
 4486                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4487
 4488                                let num_of_whitespaces = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .take_while(|c| c.is_whitespace())
 4491                                    .count();
 4492
 4493                                // 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.
 4494                                let column = start_point.column;
 4495                                let cursor_is_after_start_tag = {
 4496                                    let start_tag_len = start_tag.len();
 4497                                    let start_tag_line = snapshot
 4498                                        .chars_for_range(range.clone())
 4499                                        .skip(num_of_whitespaces)
 4500                                        .take(start_tag_len)
 4501                                        .collect::<String>();
 4502                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4503                                        num_of_whitespaces + start_tag_len <= column as usize
 4504                                    } else {
 4505                                        false
 4506                                    }
 4507                                };
 4508
 4509                                let cursor_is_after_delimiter = {
 4510                                    let delimiter_trim = delimiter.trim_end();
 4511                                    let delimiter_line = snapshot
 4512                                        .chars_for_range(range.clone())
 4513                                        .skip(num_of_whitespaces)
 4514                                        .take(delimiter_trim.len())
 4515                                        .collect::<String>();
 4516                                    if delimiter_line.starts_with(delimiter_trim) {
 4517                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4518                                    } else {
 4519                                        false
 4520                                    }
 4521                                };
 4522
 4523                                let cursor_is_before_end_tag_if_exists = {
 4524                                    let mut char_position = 0u32;
 4525                                    let mut end_tag_offset = None;
 4526
 4527                                    'outer: for chunk in snapshot.text_for_range(range) {
 4528                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4529                                            let chars_before_match =
 4530                                                chunk[..byte_pos].chars().count() as u32;
 4531                                            end_tag_offset =
 4532                                                Some(char_position + chars_before_match);
 4533                                            break 'outer;
 4534                                        }
 4535                                        char_position += chunk.chars().count() as u32;
 4536                                    }
 4537
 4538                                    if let Some(end_tag_offset) = end_tag_offset {
 4539                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4540                                        if cursor_is_after_start_tag {
 4541                                            if cursor_is_before_end_tag {
 4542                                                insert_extra_newline = true;
 4543                                            }
 4544                                            let cursor_is_at_start_of_end_tag =
 4545                                                column == end_tag_offset;
 4546                                            if cursor_is_at_start_of_end_tag {
 4547                                                indent_on_extra_newline.len = *len;
 4548                                            }
 4549                                        }
 4550                                        cursor_is_before_end_tag
 4551                                    } else {
 4552                                        true
 4553                                    }
 4554                                };
 4555
 4556                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4557                                    && cursor_is_before_end_tag_if_exists
 4558                                {
 4559                                    if cursor_is_after_start_tag {
 4560                                        indent_on_newline.len = *len;
 4561                                    }
 4562                                    Some(delimiter.clone())
 4563                                } else {
 4564                                    None
 4565                                }
 4566                            });
 4567
 4568                            (
 4569                                comment_delimiter,
 4570                                doc_delimiter,
 4571                                insert_extra_newline,
 4572                                indent_on_newline,
 4573                                indent_on_extra_newline,
 4574                            )
 4575                        } else {
 4576                            (
 4577                                None,
 4578                                None,
 4579                                false,
 4580                                IndentSize::default(),
 4581                                IndentSize::default(),
 4582                            )
 4583                        };
 4584
 4585                        let prevent_auto_indent = doc_delimiter.is_some();
 4586                        let delimiter = comment_delimiter.or(doc_delimiter);
 4587
 4588                        let capacity_for_delimiter =
 4589                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4590                        let mut new_text = String::with_capacity(
 4591                            1 + capacity_for_delimiter
 4592                                + existing_indent.len as usize
 4593                                + indent_on_newline.len as usize
 4594                                + indent_on_extra_newline.len as usize,
 4595                        );
 4596                        new_text.push('\n');
 4597                        new_text.extend(existing_indent.chars());
 4598                        new_text.extend(indent_on_newline.chars());
 4599
 4600                        if let Some(delimiter) = &delimiter {
 4601                            new_text.push_str(delimiter);
 4602                        }
 4603
 4604                        if insert_extra_newline {
 4605                            new_text.push('\n');
 4606                            new_text.extend(existing_indent.chars());
 4607                            new_text.extend(indent_on_extra_newline.chars());
 4608                        }
 4609
 4610                        let anchor = buffer.anchor_after(end);
 4611                        let new_selection = selection.map(|_| anchor);
 4612                        (
 4613                            ((start..end, new_text), prevent_auto_indent),
 4614                            (insert_extra_newline, new_selection),
 4615                        )
 4616                    })
 4617                    .unzip()
 4618            };
 4619
 4620            let mut auto_indent_edits = Vec::new();
 4621            let mut edits = Vec::new();
 4622            for (edit, prevent_auto_indent) in edits_with_flags {
 4623                if prevent_auto_indent {
 4624                    edits.push(edit);
 4625                } else {
 4626                    auto_indent_edits.push(edit);
 4627                }
 4628            }
 4629            if !edits.is_empty() {
 4630                this.edit(edits, cx);
 4631            }
 4632            if !auto_indent_edits.is_empty() {
 4633                this.edit_with_autoindent(auto_indent_edits, cx);
 4634            }
 4635
 4636            let buffer = this.buffer.read(cx).snapshot(cx);
 4637            let new_selections = selection_info
 4638                .into_iter()
 4639                .map(|(extra_newline_inserted, new_selection)| {
 4640                    let mut cursor = new_selection.end.to_point(&buffer);
 4641                    if extra_newline_inserted {
 4642                        cursor.row -= 1;
 4643                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4644                    }
 4645                    new_selection.map(|_| cursor)
 4646                })
 4647                .collect();
 4648
 4649            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4650            this.refresh_edit_prediction(true, false, window, cx);
 4651        });
 4652    }
 4653
 4654    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4656
 4657        let buffer = self.buffer.read(cx);
 4658        let snapshot = buffer.snapshot(cx);
 4659
 4660        let mut edits = Vec::new();
 4661        let mut rows = Vec::new();
 4662
 4663        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4664            let cursor = selection.head();
 4665            let row = cursor.row;
 4666
 4667            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4668
 4669            let newline = "\n".to_string();
 4670            edits.push((start_of_line..start_of_line, newline));
 4671
 4672            rows.push(row + rows_inserted as u32);
 4673        }
 4674
 4675        self.transact(window, cx, |editor, window, cx| {
 4676            editor.edit(edits, cx);
 4677
 4678            editor.change_selections(Default::default(), window, cx, |s| {
 4679                let mut index = 0;
 4680                s.move_cursors_with(|map, _, _| {
 4681                    let row = rows[index];
 4682                    index += 1;
 4683
 4684                    let point = Point::new(row, 0);
 4685                    let boundary = map.next_line_boundary(point).1;
 4686                    let clipped = map.clip_point(boundary, Bias::Left);
 4687
 4688                    (clipped, SelectionGoal::None)
 4689                });
 4690            });
 4691
 4692            let mut indent_edits = Vec::new();
 4693            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4694            for row in rows {
 4695                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4696                for (row, indent) in indents {
 4697                    if indent.len == 0 {
 4698                        continue;
 4699                    }
 4700
 4701                    let text = match indent.kind {
 4702                        IndentKind::Space => " ".repeat(indent.len as usize),
 4703                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4704                    };
 4705                    let point = Point::new(row.0, 0);
 4706                    indent_edits.push((point..point, text));
 4707                }
 4708            }
 4709            editor.edit(indent_edits, cx);
 4710        });
 4711    }
 4712
 4713    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4714        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4715
 4716        let buffer = self.buffer.read(cx);
 4717        let snapshot = buffer.snapshot(cx);
 4718
 4719        let mut edits = Vec::new();
 4720        let mut rows = Vec::new();
 4721        let mut rows_inserted = 0;
 4722
 4723        for selection in self.selections.all_adjusted(cx) {
 4724            let cursor = selection.head();
 4725            let row = cursor.row;
 4726
 4727            let point = Point::new(row + 1, 0);
 4728            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4729
 4730            let newline = "\n".to_string();
 4731            edits.push((start_of_line..start_of_line, newline));
 4732
 4733            rows_inserted += 1;
 4734            rows.push(row + rows_inserted);
 4735        }
 4736
 4737        self.transact(window, cx, |editor, window, cx| {
 4738            editor.edit(edits, cx);
 4739
 4740            editor.change_selections(Default::default(), window, cx, |s| {
 4741                let mut index = 0;
 4742                s.move_cursors_with(|map, _, _| {
 4743                    let row = rows[index];
 4744                    index += 1;
 4745
 4746                    let point = Point::new(row, 0);
 4747                    let boundary = map.next_line_boundary(point).1;
 4748                    let clipped = map.clip_point(boundary, Bias::Left);
 4749
 4750                    (clipped, SelectionGoal::None)
 4751                });
 4752            });
 4753
 4754            let mut indent_edits = Vec::new();
 4755            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4756            for row in rows {
 4757                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4758                for (row, indent) in indents {
 4759                    if indent.len == 0 {
 4760                        continue;
 4761                    }
 4762
 4763                    let text = match indent.kind {
 4764                        IndentKind::Space => " ".repeat(indent.len as usize),
 4765                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4766                    };
 4767                    let point = Point::new(row.0, 0);
 4768                    indent_edits.push((point..point, text));
 4769                }
 4770            }
 4771            editor.edit(indent_edits, cx);
 4772        });
 4773    }
 4774
 4775    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4776        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4777            original_indent_columns: Vec::new(),
 4778        });
 4779        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4780    }
 4781
 4782    fn insert_with_autoindent_mode(
 4783        &mut self,
 4784        text: &str,
 4785        autoindent_mode: Option<AutoindentMode>,
 4786        window: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        if self.read_only(cx) {
 4790            return;
 4791        }
 4792
 4793        let text: Arc<str> = text.into();
 4794        self.transact(window, cx, |this, window, cx| {
 4795            let old_selections = this.selections.all_adjusted(cx);
 4796            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4797                let anchors = {
 4798                    let snapshot = buffer.read(cx);
 4799                    old_selections
 4800                        .iter()
 4801                        .map(|s| {
 4802                            let anchor = snapshot.anchor_after(s.head());
 4803                            s.map(|_| anchor)
 4804                        })
 4805                        .collect::<Vec<_>>()
 4806                };
 4807                buffer.edit(
 4808                    old_selections
 4809                        .iter()
 4810                        .map(|s| (s.start..s.end, text.clone())),
 4811                    autoindent_mode,
 4812                    cx,
 4813                );
 4814                anchors
 4815            });
 4816
 4817            this.change_selections(Default::default(), window, cx, |s| {
 4818                s.select_anchors(selection_anchors);
 4819            });
 4820
 4821            cx.notify();
 4822        });
 4823    }
 4824
 4825    fn trigger_completion_on_input(
 4826        &mut self,
 4827        text: &str,
 4828        trigger_in_words: bool,
 4829        window: &mut Window,
 4830        cx: &mut Context<Self>,
 4831    ) {
 4832        let completions_source = self
 4833            .context_menu
 4834            .borrow()
 4835            .as_ref()
 4836            .and_then(|menu| match menu {
 4837                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4838                CodeContextMenu::CodeActions(_) => None,
 4839            });
 4840
 4841        match completions_source {
 4842            Some(CompletionsMenuSource::Words) => {
 4843                self.show_word_completions(&ShowWordCompletions, window, cx)
 4844            }
 4845            Some(CompletionsMenuSource::Normal)
 4846            | Some(CompletionsMenuSource::SnippetChoices)
 4847            | None
 4848                if self.is_completion_trigger(
 4849                    text,
 4850                    trigger_in_words,
 4851                    completions_source.is_some(),
 4852                    cx,
 4853                ) =>
 4854            {
 4855                self.show_completions(
 4856                    &ShowCompletions {
 4857                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4858                    },
 4859                    window,
 4860                    cx,
 4861                )
 4862            }
 4863            _ => {
 4864                self.hide_context_menu(window, cx);
 4865            }
 4866        }
 4867    }
 4868
 4869    fn is_completion_trigger(
 4870        &self,
 4871        text: &str,
 4872        trigger_in_words: bool,
 4873        menu_is_open: bool,
 4874        cx: &mut Context<Self>,
 4875    ) -> bool {
 4876        let position = self.selections.newest_anchor().head();
 4877        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4878            return false;
 4879        };
 4880
 4881        if let Some(completion_provider) = &self.completion_provider {
 4882            completion_provider.is_completion_trigger(
 4883                &buffer,
 4884                position.text_anchor,
 4885                text,
 4886                trigger_in_words,
 4887                menu_is_open,
 4888                cx,
 4889            )
 4890        } else {
 4891            false
 4892        }
 4893    }
 4894
 4895    /// If any empty selections is touching the start of its innermost containing autoclose
 4896    /// region, expand it to select the brackets.
 4897    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4898        let selections = self.selections.all::<usize>(cx);
 4899        let buffer = self.buffer.read(cx).read(cx);
 4900        let new_selections = self
 4901            .selections_with_autoclose_regions(selections, &buffer)
 4902            .map(|(mut selection, region)| {
 4903                if !selection.is_empty() {
 4904                    return selection;
 4905                }
 4906
 4907                if let Some(region) = region {
 4908                    let mut range = region.range.to_offset(&buffer);
 4909                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4910                        range.start -= region.pair.start.len();
 4911                        if buffer.contains_str_at(range.start, &region.pair.start)
 4912                            && buffer.contains_str_at(range.end, &region.pair.end)
 4913                        {
 4914                            range.end += region.pair.end.len();
 4915                            selection.start = range.start;
 4916                            selection.end = range.end;
 4917
 4918                            return selection;
 4919                        }
 4920                    }
 4921                }
 4922
 4923                let always_treat_brackets_as_autoclosed = buffer
 4924                    .language_settings_at(selection.start, cx)
 4925                    .always_treat_brackets_as_autoclosed;
 4926
 4927                if !always_treat_brackets_as_autoclosed {
 4928                    return selection;
 4929                }
 4930
 4931                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4932                    for (pair, enabled) in scope.brackets() {
 4933                        if !enabled || !pair.close {
 4934                            continue;
 4935                        }
 4936
 4937                        if buffer.contains_str_at(selection.start, &pair.end) {
 4938                            let pair_start_len = pair.start.len();
 4939                            if buffer.contains_str_at(
 4940                                selection.start.saturating_sub(pair_start_len),
 4941                                &pair.start,
 4942                            ) {
 4943                                selection.start -= pair_start_len;
 4944                                selection.end += pair.end.len();
 4945
 4946                                return selection;
 4947                            }
 4948                        }
 4949                    }
 4950                }
 4951
 4952                selection
 4953            })
 4954            .collect();
 4955
 4956        drop(buffer);
 4957        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4958            selections.select(new_selections)
 4959        });
 4960    }
 4961
 4962    /// Iterate the given selections, and for each one, find the smallest surrounding
 4963    /// autoclose region. This uses the ordering of the selections and the autoclose
 4964    /// regions to avoid repeated comparisons.
 4965    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4966        &'a self,
 4967        selections: impl IntoIterator<Item = Selection<D>>,
 4968        buffer: &'a MultiBufferSnapshot,
 4969    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4970        let mut i = 0;
 4971        let mut regions = self.autoclose_regions.as_slice();
 4972        selections.into_iter().map(move |selection| {
 4973            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4974
 4975            let mut enclosing = None;
 4976            while let Some(pair_state) = regions.get(i) {
 4977                if pair_state.range.end.to_offset(buffer) < range.start {
 4978                    regions = &regions[i + 1..];
 4979                    i = 0;
 4980                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4981                    break;
 4982                } else {
 4983                    if pair_state.selection_id == selection.id {
 4984                        enclosing = Some(pair_state);
 4985                    }
 4986                    i += 1;
 4987                }
 4988            }
 4989
 4990            (selection, enclosing)
 4991        })
 4992    }
 4993
 4994    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4995    fn invalidate_autoclose_regions(
 4996        &mut self,
 4997        mut selections: &[Selection<Anchor>],
 4998        buffer: &MultiBufferSnapshot,
 4999    ) {
 5000        self.autoclose_regions.retain(|state| {
 5001            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5002                return false;
 5003            }
 5004
 5005            let mut i = 0;
 5006            while let Some(selection) = selections.get(i) {
 5007                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5008                    selections = &selections[1..];
 5009                    continue;
 5010                }
 5011                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5012                    break;
 5013                }
 5014                if selection.id == state.selection_id {
 5015                    return true;
 5016                } else {
 5017                    i += 1;
 5018                }
 5019            }
 5020            false
 5021        });
 5022    }
 5023
 5024    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5025        let offset = position.to_offset(buffer);
 5026        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5027        if offset > word_range.start && kind == Some(CharKind::Word) {
 5028            Some(
 5029                buffer
 5030                    .text_for_range(word_range.start..offset)
 5031                    .collect::<String>(),
 5032            )
 5033        } else {
 5034            None
 5035        }
 5036    }
 5037
 5038    pub fn toggle_inline_values(
 5039        &mut self,
 5040        _: &ToggleInlineValues,
 5041        _: &mut Window,
 5042        cx: &mut Context<Self>,
 5043    ) {
 5044        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5045
 5046        self.refresh_inline_values(cx);
 5047    }
 5048
 5049    pub fn toggle_inlay_hints(
 5050        &mut self,
 5051        _: &ToggleInlayHints,
 5052        _: &mut Window,
 5053        cx: &mut Context<Self>,
 5054    ) {
 5055        self.refresh_inlay_hints(
 5056            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5057            cx,
 5058        );
 5059    }
 5060
 5061    pub fn inlay_hints_enabled(&self) -> bool {
 5062        self.inlay_hint_cache.enabled
 5063    }
 5064
 5065    pub fn inline_values_enabled(&self) -> bool {
 5066        self.inline_value_cache.enabled
 5067    }
 5068
 5069    #[cfg(any(test, feature = "test-support"))]
 5070    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5071        self.display_map
 5072            .read(cx)
 5073            .current_inlays()
 5074            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5075            .cloned()
 5076            .collect()
 5077    }
 5078
 5079    #[cfg(any(test, feature = "test-support"))]
 5080    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5081        self.display_map
 5082            .read(cx)
 5083            .current_inlays()
 5084            .cloned()
 5085            .collect()
 5086    }
 5087
 5088    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5089        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5090            return;
 5091        }
 5092
 5093        let reason_description = reason.description();
 5094        let ignore_debounce = matches!(
 5095            reason,
 5096            InlayHintRefreshReason::SettingsChange(_)
 5097                | InlayHintRefreshReason::Toggle(_)
 5098                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5099                | InlayHintRefreshReason::ModifiersChanged(_)
 5100        );
 5101        let (invalidate_cache, required_languages) = match reason {
 5102            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5103                match self.inlay_hint_cache.modifiers_override(enabled) {
 5104                    Some(enabled) => {
 5105                        if enabled {
 5106                            (InvalidationStrategy::RefreshRequested, None)
 5107                        } else {
 5108                            self.splice_inlays(
 5109                                &self
 5110                                    .visible_inlay_hints(cx)
 5111                                    .iter()
 5112                                    .map(|inlay| inlay.id)
 5113                                    .collect::<Vec<InlayId>>(),
 5114                                Vec::new(),
 5115                                cx,
 5116                            );
 5117                            return;
 5118                        }
 5119                    }
 5120                    None => return,
 5121                }
 5122            }
 5123            InlayHintRefreshReason::Toggle(enabled) => {
 5124                if self.inlay_hint_cache.toggle(enabled) {
 5125                    if enabled {
 5126                        (InvalidationStrategy::RefreshRequested, None)
 5127                    } else {
 5128                        self.splice_inlays(
 5129                            &self
 5130                                .visible_inlay_hints(cx)
 5131                                .iter()
 5132                                .map(|inlay| inlay.id)
 5133                                .collect::<Vec<InlayId>>(),
 5134                            Vec::new(),
 5135                            cx,
 5136                        );
 5137                        return;
 5138                    }
 5139                } else {
 5140                    return;
 5141                }
 5142            }
 5143            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5144                match self.inlay_hint_cache.update_settings(
 5145                    &self.buffer,
 5146                    new_settings,
 5147                    self.visible_inlay_hints(cx),
 5148                    cx,
 5149                ) {
 5150                    ControlFlow::Break(Some(InlaySplice {
 5151                        to_remove,
 5152                        to_insert,
 5153                    })) => {
 5154                        self.splice_inlays(&to_remove, to_insert, cx);
 5155                        return;
 5156                    }
 5157                    ControlFlow::Break(None) => return,
 5158                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5159                }
 5160            }
 5161            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5162                if let Some(InlaySplice {
 5163                    to_remove,
 5164                    to_insert,
 5165                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5166                {
 5167                    self.splice_inlays(&to_remove, to_insert, cx);
 5168                }
 5169                self.display_map.update(cx, |display_map, _| {
 5170                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5171                });
 5172                return;
 5173            }
 5174            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5175            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5176                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5177            }
 5178            InlayHintRefreshReason::RefreshRequested => {
 5179                (InvalidationStrategy::RefreshRequested, None)
 5180            }
 5181        };
 5182
 5183        if let Some(InlaySplice {
 5184            to_remove,
 5185            to_insert,
 5186        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5187            reason_description,
 5188            self.visible_excerpts(required_languages.as_ref(), cx),
 5189            invalidate_cache,
 5190            ignore_debounce,
 5191            cx,
 5192        ) {
 5193            self.splice_inlays(&to_remove, to_insert, cx);
 5194        }
 5195    }
 5196
 5197    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5198        self.display_map
 5199            .read(cx)
 5200            .current_inlays()
 5201            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5202            .cloned()
 5203            .collect()
 5204    }
 5205
 5206    pub fn visible_excerpts(
 5207        &self,
 5208        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5209        cx: &mut Context<Editor>,
 5210    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5211        let Some(project) = self.project() else {
 5212            return HashMap::default();
 5213        };
 5214        let project = project.read(cx);
 5215        let multi_buffer = self.buffer().read(cx);
 5216        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5217        let multi_buffer_visible_start = self
 5218            .scroll_manager
 5219            .anchor()
 5220            .anchor
 5221            .to_point(&multi_buffer_snapshot);
 5222        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5223            multi_buffer_visible_start
 5224                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5225            Bias::Left,
 5226        );
 5227        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5228        multi_buffer_snapshot
 5229            .range_to_buffer_ranges(multi_buffer_visible_range)
 5230            .into_iter()
 5231            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5232            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5233                let buffer_file = project::File::from_dyn(buffer.file())?;
 5234                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5235                let worktree_entry = buffer_worktree
 5236                    .read(cx)
 5237                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5238                if worktree_entry.is_ignored {
 5239                    return None;
 5240                }
 5241
 5242                let language = buffer.language()?;
 5243                if let Some(restrict_to_languages) = restrict_to_languages
 5244                    && !restrict_to_languages.contains(language)
 5245                {
 5246                    return None;
 5247                }
 5248                Some((
 5249                    excerpt_id,
 5250                    (
 5251                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5252                        buffer.version().clone(),
 5253                        excerpt_visible_range,
 5254                    ),
 5255                ))
 5256            })
 5257            .collect()
 5258    }
 5259
 5260    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5261        TextLayoutDetails {
 5262            text_system: window.text_system().clone(),
 5263            editor_style: self.style.clone().unwrap(),
 5264            rem_size: window.rem_size(),
 5265            scroll_anchor: self.scroll_manager.anchor(),
 5266            visible_rows: self.visible_line_count(),
 5267            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5268        }
 5269    }
 5270
 5271    pub fn splice_inlays(
 5272        &self,
 5273        to_remove: &[InlayId],
 5274        to_insert: Vec<Inlay>,
 5275        cx: &mut Context<Self>,
 5276    ) {
 5277        self.display_map.update(cx, |display_map, cx| {
 5278            display_map.splice_inlays(to_remove, to_insert, cx)
 5279        });
 5280        cx.notify();
 5281    }
 5282
 5283    fn trigger_on_type_formatting(
 5284        &self,
 5285        input: String,
 5286        window: &mut Window,
 5287        cx: &mut Context<Self>,
 5288    ) -> Option<Task<Result<()>>> {
 5289        if input.len() != 1 {
 5290            return None;
 5291        }
 5292
 5293        let project = self.project()?;
 5294        let position = self.selections.newest_anchor().head();
 5295        let (buffer, buffer_position) = self
 5296            .buffer
 5297            .read(cx)
 5298            .text_anchor_for_position(position, cx)?;
 5299
 5300        let settings = language_settings::language_settings(
 5301            buffer
 5302                .read(cx)
 5303                .language_at(buffer_position)
 5304                .map(|l| l.name()),
 5305            buffer.read(cx).file(),
 5306            cx,
 5307        );
 5308        if !settings.use_on_type_format {
 5309            return None;
 5310        }
 5311
 5312        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5313        // hence we do LSP request & edit on host side only — add formats to host's history.
 5314        let push_to_lsp_host_history = true;
 5315        // If this is not the host, append its history with new edits.
 5316        let push_to_client_history = project.read(cx).is_via_collab();
 5317
 5318        let on_type_formatting = project.update(cx, |project, cx| {
 5319            project.on_type_format(
 5320                buffer.clone(),
 5321                buffer_position,
 5322                input,
 5323                push_to_lsp_host_history,
 5324                cx,
 5325            )
 5326        });
 5327        Some(cx.spawn_in(window, async move |editor, cx| {
 5328            if let Some(transaction) = on_type_formatting.await? {
 5329                if push_to_client_history {
 5330                    buffer
 5331                        .update(cx, |buffer, _| {
 5332                            buffer.push_transaction(transaction, Instant::now());
 5333                            buffer.finalize_last_transaction();
 5334                        })
 5335                        .ok();
 5336                }
 5337                editor.update(cx, |editor, cx| {
 5338                    editor.refresh_document_highlights(cx);
 5339                })?;
 5340            }
 5341            Ok(())
 5342        }))
 5343    }
 5344
 5345    pub fn show_word_completions(
 5346        &mut self,
 5347        _: &ShowWordCompletions,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) {
 5351        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5352    }
 5353
 5354    pub fn show_completions(
 5355        &mut self,
 5356        options: &ShowCompletions,
 5357        window: &mut Window,
 5358        cx: &mut Context<Self>,
 5359    ) {
 5360        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5361    }
 5362
 5363    fn open_or_update_completions_menu(
 5364        &mut self,
 5365        requested_source: Option<CompletionsMenuSource>,
 5366        trigger: Option<&str>,
 5367        window: &mut Window,
 5368        cx: &mut Context<Self>,
 5369    ) {
 5370        if self.pending_rename.is_some() {
 5371            return;
 5372        }
 5373
 5374        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5375
 5376        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5377        // inserted and selected. To handle that case, the start of the selection is used so that
 5378        // the menu starts with all choices.
 5379        let position = self
 5380            .selections
 5381            .newest_anchor()
 5382            .start
 5383            .bias_right(&multibuffer_snapshot);
 5384        if position.diff_base_anchor.is_some() {
 5385            return;
 5386        }
 5387        let (buffer, buffer_position) =
 5388            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5389                output
 5390            } else {
 5391                return;
 5392            };
 5393        let buffer_snapshot = buffer.read(cx).snapshot();
 5394
 5395        let query: Option<Arc<String>> =
 5396            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5397
 5398        drop(multibuffer_snapshot);
 5399
 5400        let provider = match requested_source {
 5401            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5402            Some(CompletionsMenuSource::Words) => None,
 5403            Some(CompletionsMenuSource::SnippetChoices) => {
 5404                log::error!("bug: SnippetChoices requested_source is not handled");
 5405                None
 5406            }
 5407        };
 5408
 5409        let sort_completions = provider
 5410            .as_ref()
 5411            .is_some_and(|provider| provider.sort_completions());
 5412
 5413        let filter_completions = provider
 5414            .as_ref()
 5415            .is_none_or(|provider| provider.filter_completions());
 5416
 5417        let trigger_kind = match trigger {
 5418            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5419                CompletionTriggerKind::TRIGGER_CHARACTER
 5420            }
 5421            _ => CompletionTriggerKind::INVOKED,
 5422        };
 5423        let completion_context = CompletionContext {
 5424            trigger_character: trigger.and_then(|trigger| {
 5425                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5426                    Some(String::from(trigger))
 5427                } else {
 5428                    None
 5429                }
 5430            }),
 5431            trigger_kind,
 5432        };
 5433
 5434        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5435        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5436        // involve trigger chars, so this is skipped in that case.
 5437        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5438        {
 5439            let menu_is_open = matches!(
 5440                self.context_menu.borrow().as_ref(),
 5441                Some(CodeContextMenu::Completions(_))
 5442            );
 5443            if menu_is_open {
 5444                self.hide_context_menu(window, cx);
 5445            }
 5446        }
 5447
 5448        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5449            if filter_completions {
 5450                menu.filter(query.clone(), provider.clone(), window, cx);
 5451            }
 5452            // When `is_incomplete` is false, no need to re-query completions when the current query
 5453            // is a suffix of the initial query.
 5454            if !menu.is_incomplete {
 5455                // If the new query is a suffix of the old query (typing more characters) and
 5456                // the previous result was complete, the existing completions can be filtered.
 5457                //
 5458                // Note that this is always true for snippet completions.
 5459                let query_matches = match (&menu.initial_query, &query) {
 5460                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5461                    (None, _) => true,
 5462                    _ => false,
 5463                };
 5464                if query_matches {
 5465                    let position_matches = if menu.initial_position == position {
 5466                        true
 5467                    } else {
 5468                        let snapshot = self.buffer.read(cx).read(cx);
 5469                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5470                    };
 5471                    if position_matches {
 5472                        return;
 5473                    }
 5474                }
 5475            }
 5476        };
 5477
 5478        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5479            buffer_snapshot.surrounding_word(buffer_position, false)
 5480        {
 5481            let word_to_exclude = buffer_snapshot
 5482                .text_for_range(word_range.clone())
 5483                .collect::<String>();
 5484            (
 5485                buffer_snapshot.anchor_before(word_range.start)
 5486                    ..buffer_snapshot.anchor_after(buffer_position),
 5487                Some(word_to_exclude),
 5488            )
 5489        } else {
 5490            (buffer_position..buffer_position, None)
 5491        };
 5492
 5493        let language = buffer_snapshot
 5494            .language_at(buffer_position)
 5495            .map(|language| language.name());
 5496
 5497        let completion_settings =
 5498            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5499
 5500        let show_completion_documentation = buffer_snapshot
 5501            .settings_at(buffer_position, cx)
 5502            .show_completion_documentation;
 5503
 5504        // The document can be large, so stay in reasonable bounds when searching for words,
 5505        // otherwise completion pop-up might be slow to appear.
 5506        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5507        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5508        let min_word_search = buffer_snapshot.clip_point(
 5509            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5510            Bias::Left,
 5511        );
 5512        let max_word_search = buffer_snapshot.clip_point(
 5513            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5514            Bias::Right,
 5515        );
 5516        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5517            ..buffer_snapshot.point_to_offset(max_word_search);
 5518
 5519        let skip_digits = query
 5520            .as_ref()
 5521            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5522
 5523        let (mut words, provider_responses) = match &provider {
 5524            Some(provider) => {
 5525                let provider_responses = provider.completions(
 5526                    position.excerpt_id,
 5527                    &buffer,
 5528                    buffer_position,
 5529                    completion_context,
 5530                    window,
 5531                    cx,
 5532                );
 5533
 5534                let words = match completion_settings.words {
 5535                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5536                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5537                        .background_spawn(async move {
 5538                            buffer_snapshot.words_in_range(WordsQuery {
 5539                                fuzzy_contents: None,
 5540                                range: word_search_range,
 5541                                skip_digits,
 5542                            })
 5543                        }),
 5544                };
 5545
 5546                (words, provider_responses)
 5547            }
 5548            None => (
 5549                cx.background_spawn(async move {
 5550                    buffer_snapshot.words_in_range(WordsQuery {
 5551                        fuzzy_contents: None,
 5552                        range: word_search_range,
 5553                        skip_digits,
 5554                    })
 5555                }),
 5556                Task::ready(Ok(Vec::new())),
 5557            ),
 5558        };
 5559
 5560        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5561
 5562        let id = post_inc(&mut self.next_completion_id);
 5563        let task = cx.spawn_in(window, async move |editor, cx| {
 5564            let Ok(()) = editor.update(cx, |this, _| {
 5565                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5566            }) else {
 5567                return;
 5568            };
 5569
 5570            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5571            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5572            let mut completions = Vec::new();
 5573            let mut is_incomplete = false;
 5574            if let Some(provider_responses) = provider_responses.await.log_err()
 5575                && !provider_responses.is_empty()
 5576            {
 5577                for response in provider_responses {
 5578                    completions.extend(response.completions);
 5579                    is_incomplete = is_incomplete || response.is_incomplete;
 5580                }
 5581                if completion_settings.words == WordsCompletionMode::Fallback {
 5582                    words = Task::ready(BTreeMap::default());
 5583                }
 5584            }
 5585
 5586            let mut words = words.await;
 5587            if let Some(word_to_exclude) = &word_to_exclude {
 5588                words.remove(word_to_exclude);
 5589            }
 5590            for lsp_completion in &completions {
 5591                words.remove(&lsp_completion.new_text);
 5592            }
 5593            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5594                replace_range: word_replace_range.clone(),
 5595                new_text: word.clone(),
 5596                label: CodeLabel::plain(word, None),
 5597                icon_path: None,
 5598                documentation: None,
 5599                source: CompletionSource::BufferWord {
 5600                    word_range,
 5601                    resolved: false,
 5602                },
 5603                insert_text_mode: Some(InsertTextMode::AS_IS),
 5604                confirm: None,
 5605            }));
 5606
 5607            let menu = if completions.is_empty() {
 5608                None
 5609            } else {
 5610                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5611                    let languages = editor
 5612                        .workspace
 5613                        .as_ref()
 5614                        .and_then(|(workspace, _)| workspace.upgrade())
 5615                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5616                    let menu = CompletionsMenu::new(
 5617                        id,
 5618                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5619                        sort_completions,
 5620                        show_completion_documentation,
 5621                        position,
 5622                        query.clone(),
 5623                        is_incomplete,
 5624                        buffer.clone(),
 5625                        completions.into(),
 5626                        snippet_sort_order,
 5627                        languages,
 5628                        language,
 5629                        cx,
 5630                    );
 5631
 5632                    let query = if filter_completions { query } else { None };
 5633                    let matches_task = if let Some(query) = query {
 5634                        menu.do_async_filtering(query, cx)
 5635                    } else {
 5636                        Task::ready(menu.unfiltered_matches())
 5637                    };
 5638                    (menu, matches_task)
 5639                }) else {
 5640                    return;
 5641                };
 5642
 5643                let matches = matches_task.await;
 5644
 5645                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5646                    // Newer menu already set, so exit.
 5647                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5648                        editor.context_menu.borrow().as_ref()
 5649                        && prev_menu.id > id
 5650                    {
 5651                        return;
 5652                    };
 5653
 5654                    // Only valid to take prev_menu because it the new menu is immediately set
 5655                    // below, or the menu is hidden.
 5656                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5657                        editor.context_menu.borrow_mut().take()
 5658                    {
 5659                        let position_matches =
 5660                            if prev_menu.initial_position == menu.initial_position {
 5661                                true
 5662                            } else {
 5663                                let snapshot = editor.buffer.read(cx).read(cx);
 5664                                prev_menu.initial_position.to_offset(&snapshot)
 5665                                    == menu.initial_position.to_offset(&snapshot)
 5666                            };
 5667                        if position_matches {
 5668                            // Preserve markdown cache before `set_filter_results` because it will
 5669                            // try to populate the documentation cache.
 5670                            menu.preserve_markdown_cache(prev_menu);
 5671                        }
 5672                    };
 5673
 5674                    menu.set_filter_results(matches, provider, window, cx);
 5675                }) else {
 5676                    return;
 5677                };
 5678
 5679                menu.visible().then_some(menu)
 5680            };
 5681
 5682            editor
 5683                .update_in(cx, |editor, window, cx| {
 5684                    if editor.focus_handle.is_focused(window)
 5685                        && let Some(menu) = menu
 5686                    {
 5687                        *editor.context_menu.borrow_mut() =
 5688                            Some(CodeContextMenu::Completions(menu));
 5689
 5690                        crate::hover_popover::hide_hover(editor, cx);
 5691                        if editor.show_edit_predictions_in_menu() {
 5692                            editor.update_visible_edit_prediction(window, cx);
 5693                        } else {
 5694                            editor.discard_edit_prediction(false, cx);
 5695                        }
 5696
 5697                        cx.notify();
 5698                        return;
 5699                    }
 5700
 5701                    if editor.completion_tasks.len() <= 1 {
 5702                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5703                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5704                        // If it was already hidden and we don't show edit predictions in the menu,
 5705                        // we should also show the edit prediction when available.
 5706                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5707                            editor.update_visible_edit_prediction(window, cx);
 5708                        }
 5709                    }
 5710                })
 5711                .ok();
 5712        });
 5713
 5714        self.completion_tasks.push((id, task));
 5715    }
 5716
 5717    #[cfg(feature = "test-support")]
 5718    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5719        let menu = self.context_menu.borrow();
 5720        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5721            let completions = menu.completions.borrow();
 5722            Some(completions.to_vec())
 5723        } else {
 5724            None
 5725        }
 5726    }
 5727
 5728    pub fn with_completions_menu_matching_id<R>(
 5729        &self,
 5730        id: CompletionId,
 5731        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5732    ) -> R {
 5733        let mut context_menu = self.context_menu.borrow_mut();
 5734        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5735            return f(None);
 5736        };
 5737        if completions_menu.id != id {
 5738            return f(None);
 5739        }
 5740        f(Some(completions_menu))
 5741    }
 5742
 5743    pub fn confirm_completion(
 5744        &mut self,
 5745        action: &ConfirmCompletion,
 5746        window: &mut Window,
 5747        cx: &mut Context<Self>,
 5748    ) -> Option<Task<Result<()>>> {
 5749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5750        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5751    }
 5752
 5753    pub fn confirm_completion_insert(
 5754        &mut self,
 5755        _: &ConfirmCompletionInsert,
 5756        window: &mut Window,
 5757        cx: &mut Context<Self>,
 5758    ) -> Option<Task<Result<()>>> {
 5759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5760        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5761    }
 5762
 5763    pub fn confirm_completion_replace(
 5764        &mut self,
 5765        _: &ConfirmCompletionReplace,
 5766        window: &mut Window,
 5767        cx: &mut Context<Self>,
 5768    ) -> Option<Task<Result<()>>> {
 5769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5770        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5771    }
 5772
 5773    pub fn compose_completion(
 5774        &mut self,
 5775        action: &ComposeCompletion,
 5776        window: &mut Window,
 5777        cx: &mut Context<Self>,
 5778    ) -> Option<Task<Result<()>>> {
 5779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5780        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5781    }
 5782
 5783    fn do_completion(
 5784        &mut self,
 5785        item_ix: Option<usize>,
 5786        intent: CompletionIntent,
 5787        window: &mut Window,
 5788        cx: &mut Context<Editor>,
 5789    ) -> Option<Task<Result<()>>> {
 5790        use language::ToOffset as _;
 5791
 5792        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5793        else {
 5794            return None;
 5795        };
 5796
 5797        let candidate_id = {
 5798            let entries = completions_menu.entries.borrow();
 5799            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5800            if self.show_edit_predictions_in_menu() {
 5801                self.discard_edit_prediction(true, cx);
 5802            }
 5803            mat.candidate_id
 5804        };
 5805
 5806        let completion = completions_menu
 5807            .completions
 5808            .borrow()
 5809            .get(candidate_id)?
 5810            .clone();
 5811        cx.stop_propagation();
 5812
 5813        let buffer_handle = completions_menu.buffer.clone();
 5814
 5815        let CompletionEdit {
 5816            new_text,
 5817            snippet,
 5818            replace_range,
 5819        } = process_completion_for_edit(
 5820            &completion,
 5821            intent,
 5822            &buffer_handle,
 5823            &completions_menu.initial_position.text_anchor,
 5824            cx,
 5825        );
 5826
 5827        let buffer = buffer_handle.read(cx);
 5828        let snapshot = self.buffer.read(cx).snapshot(cx);
 5829        let newest_anchor = self.selections.newest_anchor();
 5830        let replace_range_multibuffer = {
 5831            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5832            let multibuffer_anchor = snapshot
 5833                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5834                .unwrap()
 5835                ..snapshot
 5836                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5837                    .unwrap();
 5838            multibuffer_anchor.start.to_offset(&snapshot)
 5839                ..multibuffer_anchor.end.to_offset(&snapshot)
 5840        };
 5841        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5842            return None;
 5843        }
 5844
 5845        let old_text = buffer
 5846            .text_for_range(replace_range.clone())
 5847            .collect::<String>();
 5848        let lookbehind = newest_anchor
 5849            .start
 5850            .text_anchor
 5851            .to_offset(buffer)
 5852            .saturating_sub(replace_range.start);
 5853        let lookahead = replace_range
 5854            .end
 5855            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5856        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5857        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5858
 5859        let selections = self.selections.all::<usize>(cx);
 5860        let mut ranges = Vec::new();
 5861        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5862
 5863        for selection in &selections {
 5864            let range = if selection.id == newest_anchor.id {
 5865                replace_range_multibuffer.clone()
 5866            } else {
 5867                let mut range = selection.range();
 5868
 5869                // if prefix is present, don't duplicate it
 5870                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5871                    range.start = range.start.saturating_sub(lookbehind);
 5872
 5873                    // if suffix is also present, mimic the newest cursor and replace it
 5874                    if selection.id != newest_anchor.id
 5875                        && snapshot.contains_str_at(range.end, suffix)
 5876                    {
 5877                        range.end += lookahead;
 5878                    }
 5879                }
 5880                range
 5881            };
 5882
 5883            ranges.push(range.clone());
 5884
 5885            if !self.linked_edit_ranges.is_empty() {
 5886                let start_anchor = snapshot.anchor_before(range.start);
 5887                let end_anchor = snapshot.anchor_after(range.end);
 5888                if let Some(ranges) = self
 5889                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5890                {
 5891                    for (buffer, edits) in ranges {
 5892                        linked_edits
 5893                            .entry(buffer.clone())
 5894                            .or_default()
 5895                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5896                    }
 5897                }
 5898            }
 5899        }
 5900
 5901        let common_prefix_len = old_text
 5902            .chars()
 5903            .zip(new_text.chars())
 5904            .take_while(|(a, b)| a == b)
 5905            .map(|(a, _)| a.len_utf8())
 5906            .sum::<usize>();
 5907
 5908        cx.emit(EditorEvent::InputHandled {
 5909            utf16_range_to_replace: None,
 5910            text: new_text[common_prefix_len..].into(),
 5911        });
 5912
 5913        self.transact(window, cx, |editor, window, cx| {
 5914            if let Some(mut snippet) = snippet {
 5915                snippet.text = new_text.to_string();
 5916                editor
 5917                    .insert_snippet(&ranges, snippet, window, cx)
 5918                    .log_err();
 5919            } else {
 5920                editor.buffer.update(cx, |multi_buffer, cx| {
 5921                    let auto_indent = match completion.insert_text_mode {
 5922                        Some(InsertTextMode::AS_IS) => None,
 5923                        _ => editor.autoindent_mode.clone(),
 5924                    };
 5925                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5926                    multi_buffer.edit(edits, auto_indent, cx);
 5927                });
 5928            }
 5929            for (buffer, edits) in linked_edits {
 5930                buffer.update(cx, |buffer, cx| {
 5931                    let snapshot = buffer.snapshot();
 5932                    let edits = edits
 5933                        .into_iter()
 5934                        .map(|(range, text)| {
 5935                            use text::ToPoint as TP;
 5936                            let end_point = TP::to_point(&range.end, &snapshot);
 5937                            let start_point = TP::to_point(&range.start, &snapshot);
 5938                            (start_point..end_point, text)
 5939                        })
 5940                        .sorted_by_key(|(range, _)| range.start);
 5941                    buffer.edit(edits, None, cx);
 5942                })
 5943            }
 5944
 5945            editor.refresh_edit_prediction(true, false, window, cx);
 5946        });
 5947        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5948
 5949        let show_new_completions_on_confirm = completion
 5950            .confirm
 5951            .as_ref()
 5952            .is_some_and(|confirm| confirm(intent, window, cx));
 5953        if show_new_completions_on_confirm {
 5954            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5955        }
 5956
 5957        let provider = self.completion_provider.as_ref()?;
 5958        drop(completion);
 5959        let apply_edits = provider.apply_additional_edits_for_completion(
 5960            buffer_handle,
 5961            completions_menu.completions.clone(),
 5962            candidate_id,
 5963            true,
 5964            cx,
 5965        );
 5966
 5967        let editor_settings = EditorSettings::get_global(cx);
 5968        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5969            // After the code completion is finished, users often want to know what signatures are needed.
 5970            // so we should automatically call signature_help
 5971            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5972        }
 5973
 5974        Some(cx.foreground_executor().spawn(async move {
 5975            apply_edits.await?;
 5976            Ok(())
 5977        }))
 5978    }
 5979
 5980    pub fn toggle_code_actions(
 5981        &mut self,
 5982        action: &ToggleCodeActions,
 5983        window: &mut Window,
 5984        cx: &mut Context<Self>,
 5985    ) {
 5986        let quick_launch = action.quick_launch;
 5987        let mut context_menu = self.context_menu.borrow_mut();
 5988        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5989            if code_actions.deployed_from == action.deployed_from {
 5990                // Toggle if we're selecting the same one
 5991                *context_menu = None;
 5992                cx.notify();
 5993                return;
 5994            } else {
 5995                // Otherwise, clear it and start a new one
 5996                *context_menu = None;
 5997                cx.notify();
 5998            }
 5999        }
 6000        drop(context_menu);
 6001        let snapshot = self.snapshot(window, cx);
 6002        let deployed_from = action.deployed_from.clone();
 6003        let action = action.clone();
 6004        self.completion_tasks.clear();
 6005        self.discard_edit_prediction(false, cx);
 6006
 6007        let multibuffer_point = match &action.deployed_from {
 6008            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6009                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6010            }
 6011            _ => self.selections.newest::<Point>(cx).head(),
 6012        };
 6013        let Some((buffer, buffer_row)) = snapshot
 6014            .buffer_snapshot
 6015            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6016            .and_then(|(buffer_snapshot, range)| {
 6017                self.buffer()
 6018                    .read(cx)
 6019                    .buffer(buffer_snapshot.remote_id())
 6020                    .map(|buffer| (buffer, range.start.row))
 6021            })
 6022        else {
 6023            return;
 6024        };
 6025        let buffer_id = buffer.read(cx).remote_id();
 6026        let tasks = self
 6027            .tasks
 6028            .get(&(buffer_id, buffer_row))
 6029            .map(|t| Arc::new(t.to_owned()));
 6030
 6031        if !self.focus_handle.is_focused(window) {
 6032            return;
 6033        }
 6034        let project = self.project.clone();
 6035
 6036        let code_actions_task = match deployed_from {
 6037            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6038            _ => self.code_actions(buffer_row, window, cx),
 6039        };
 6040
 6041        let runnable_task = match deployed_from {
 6042            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6043            _ => {
 6044                let mut task_context_task = Task::ready(None);
 6045                if let Some(tasks) = &tasks
 6046                    && let Some(project) = project
 6047                {
 6048                    task_context_task =
 6049                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6050                }
 6051
 6052                cx.spawn_in(window, {
 6053                    let buffer = buffer.clone();
 6054                    async move |editor, cx| {
 6055                        let task_context = task_context_task.await;
 6056
 6057                        let resolved_tasks =
 6058                            tasks
 6059                                .zip(task_context.clone())
 6060                                .map(|(tasks, task_context)| ResolvedTasks {
 6061                                    templates: tasks.resolve(&task_context).collect(),
 6062                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6063                                        multibuffer_point.row,
 6064                                        tasks.column,
 6065                                    )),
 6066                                });
 6067                        let debug_scenarios = editor
 6068                            .update(cx, |editor, cx| {
 6069                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6070                            })?
 6071                            .await;
 6072                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6073                    }
 6074                })
 6075            }
 6076        };
 6077
 6078        cx.spawn_in(window, async move |editor, cx| {
 6079            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6080            let code_actions = code_actions_task.await;
 6081            let spawn_straight_away = quick_launch
 6082                && resolved_tasks
 6083                    .as_ref()
 6084                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6085                && code_actions
 6086                    .as_ref()
 6087                    .is_none_or(|actions| actions.is_empty())
 6088                && debug_scenarios.is_empty();
 6089
 6090            editor.update_in(cx, |editor, window, cx| {
 6091                crate::hover_popover::hide_hover(editor, cx);
 6092                let actions = CodeActionContents::new(
 6093                    resolved_tasks,
 6094                    code_actions,
 6095                    debug_scenarios,
 6096                    task_context.unwrap_or_default(),
 6097                );
 6098
 6099                // Don't show the menu if there are no actions available
 6100                if actions.is_empty() {
 6101                    cx.notify();
 6102                    return Task::ready(Ok(()));
 6103                }
 6104
 6105                *editor.context_menu.borrow_mut() =
 6106                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6107                        buffer,
 6108                        actions,
 6109                        selected_item: Default::default(),
 6110                        scroll_handle: UniformListScrollHandle::default(),
 6111                        deployed_from,
 6112                    }));
 6113                cx.notify();
 6114                if spawn_straight_away
 6115                    && let Some(task) = editor.confirm_code_action(
 6116                        &ConfirmCodeAction { item_ix: Some(0) },
 6117                        window,
 6118                        cx,
 6119                    )
 6120                {
 6121                    return task;
 6122                }
 6123
 6124                Task::ready(Ok(()))
 6125            })
 6126        })
 6127        .detach_and_log_err(cx);
 6128    }
 6129
 6130    fn debug_scenarios(
 6131        &mut self,
 6132        resolved_tasks: &Option<ResolvedTasks>,
 6133        buffer: &Entity<Buffer>,
 6134        cx: &mut App,
 6135    ) -> Task<Vec<task::DebugScenario>> {
 6136        maybe!({
 6137            let project = self.project()?;
 6138            let dap_store = project.read(cx).dap_store();
 6139            let mut scenarios = vec![];
 6140            let resolved_tasks = resolved_tasks.as_ref()?;
 6141            let buffer = buffer.read(cx);
 6142            let language = buffer.language()?;
 6143            let file = buffer.file();
 6144            let debug_adapter = language_settings(language.name().into(), file, cx)
 6145                .debuggers
 6146                .first()
 6147                .map(SharedString::from)
 6148                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6149
 6150            dap_store.update(cx, |dap_store, cx| {
 6151                for (_, task) in &resolved_tasks.templates {
 6152                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6153                        task.original_task().clone(),
 6154                        debug_adapter.clone().into(),
 6155                        task.display_label().to_owned().into(),
 6156                        cx,
 6157                    );
 6158                    scenarios.push(maybe_scenario);
 6159                }
 6160            });
 6161            Some(cx.background_spawn(async move {
 6162                futures::future::join_all(scenarios)
 6163                    .await
 6164                    .into_iter()
 6165                    .flatten()
 6166                    .collect::<Vec<_>>()
 6167            }))
 6168        })
 6169        .unwrap_or_else(|| Task::ready(vec![]))
 6170    }
 6171
 6172    fn code_actions(
 6173        &mut self,
 6174        buffer_row: u32,
 6175        window: &mut Window,
 6176        cx: &mut Context<Self>,
 6177    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6178        let mut task = self.code_actions_task.take();
 6179        cx.spawn_in(window, async move |editor, cx| {
 6180            while let Some(prev_task) = task {
 6181                prev_task.await.log_err();
 6182                task = editor
 6183                    .update(cx, |this, _| this.code_actions_task.take())
 6184                    .ok()?;
 6185            }
 6186
 6187            editor
 6188                .update(cx, |editor, cx| {
 6189                    editor
 6190                        .available_code_actions
 6191                        .clone()
 6192                        .and_then(|(location, code_actions)| {
 6193                            let snapshot = location.buffer.read(cx).snapshot();
 6194                            let point_range = location.range.to_point(&snapshot);
 6195                            let point_range = point_range.start.row..=point_range.end.row;
 6196                            if point_range.contains(&buffer_row) {
 6197                                Some(code_actions)
 6198                            } else {
 6199                                None
 6200                            }
 6201                        })
 6202                })
 6203                .ok()
 6204                .flatten()
 6205        })
 6206    }
 6207
 6208    pub fn confirm_code_action(
 6209        &mut self,
 6210        action: &ConfirmCodeAction,
 6211        window: &mut Window,
 6212        cx: &mut Context<Self>,
 6213    ) -> Option<Task<Result<()>>> {
 6214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6215
 6216        let actions_menu =
 6217            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6218                menu
 6219            } else {
 6220                return None;
 6221            };
 6222
 6223        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6224        let action = actions_menu.actions.get(action_ix)?;
 6225        let title = action.label();
 6226        let buffer = actions_menu.buffer;
 6227        let workspace = self.workspace()?;
 6228
 6229        match action {
 6230            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6231                workspace.update(cx, |workspace, cx| {
 6232                    workspace.schedule_resolved_task(
 6233                        task_source_kind,
 6234                        resolved_task,
 6235                        false,
 6236                        window,
 6237                        cx,
 6238                    );
 6239
 6240                    Some(Task::ready(Ok(())))
 6241                })
 6242            }
 6243            CodeActionsItem::CodeAction {
 6244                excerpt_id,
 6245                action,
 6246                provider,
 6247            } => {
 6248                let apply_code_action =
 6249                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6250                let workspace = workspace.downgrade();
 6251                Some(cx.spawn_in(window, async move |editor, cx| {
 6252                    let project_transaction = apply_code_action.await?;
 6253                    Self::open_project_transaction(
 6254                        &editor,
 6255                        workspace,
 6256                        project_transaction,
 6257                        title,
 6258                        cx,
 6259                    )
 6260                    .await
 6261                }))
 6262            }
 6263            CodeActionsItem::DebugScenario(scenario) => {
 6264                let context = actions_menu.actions.context;
 6265
 6266                workspace.update(cx, |workspace, cx| {
 6267                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6268                    workspace.start_debug_session(
 6269                        scenario,
 6270                        context,
 6271                        Some(buffer),
 6272                        None,
 6273                        window,
 6274                        cx,
 6275                    );
 6276                });
 6277                Some(Task::ready(Ok(())))
 6278            }
 6279        }
 6280    }
 6281
 6282    pub async fn open_project_transaction(
 6283        this: &WeakEntity<Editor>,
 6284        workspace: WeakEntity<Workspace>,
 6285        transaction: ProjectTransaction,
 6286        title: String,
 6287        cx: &mut AsyncWindowContext,
 6288    ) -> Result<()> {
 6289        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6290        cx.update(|_, cx| {
 6291            entries.sort_unstable_by_key(|(buffer, _)| {
 6292                buffer.read(cx).file().map(|f| f.path().clone())
 6293            });
 6294        })?;
 6295
 6296        // If the project transaction's edits are all contained within this editor, then
 6297        // avoid opening a new editor to display them.
 6298
 6299        if let Some((buffer, transaction)) = entries.first() {
 6300            if entries.len() == 1 {
 6301                let excerpt = this.update(cx, |editor, cx| {
 6302                    editor
 6303                        .buffer()
 6304                        .read(cx)
 6305                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6306                })?;
 6307                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6308                    && excerpted_buffer == *buffer
 6309                {
 6310                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6311                        let excerpt_range = excerpt_range.to_offset(buffer);
 6312                        buffer
 6313                            .edited_ranges_for_transaction::<usize>(transaction)
 6314                            .all(|range| {
 6315                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6316                            })
 6317                    })?;
 6318
 6319                    if all_edits_within_excerpt {
 6320                        return Ok(());
 6321                    }
 6322                }
 6323            }
 6324        } else {
 6325            return Ok(());
 6326        }
 6327
 6328        let mut ranges_to_highlight = Vec::new();
 6329        let excerpt_buffer = cx.new(|cx| {
 6330            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6331            for (buffer_handle, transaction) in &entries {
 6332                let edited_ranges = buffer_handle
 6333                    .read(cx)
 6334                    .edited_ranges_for_transaction::<Point>(transaction)
 6335                    .collect::<Vec<_>>();
 6336                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6337                    PathKey::for_buffer(buffer_handle, cx),
 6338                    buffer_handle.clone(),
 6339                    edited_ranges,
 6340                    DEFAULT_MULTIBUFFER_CONTEXT,
 6341                    cx,
 6342                );
 6343
 6344                ranges_to_highlight.extend(ranges);
 6345            }
 6346            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6347            multibuffer
 6348        })?;
 6349
 6350        workspace.update_in(cx, |workspace, window, cx| {
 6351            let project = workspace.project().clone();
 6352            let editor =
 6353                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6354            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6355            editor.update(cx, |editor, cx| {
 6356                editor.highlight_background::<Self>(
 6357                    &ranges_to_highlight,
 6358                    |theme| theme.colors().editor_highlighted_line_background,
 6359                    cx,
 6360                );
 6361            });
 6362        })?;
 6363
 6364        Ok(())
 6365    }
 6366
 6367    pub fn clear_code_action_providers(&mut self) {
 6368        self.code_action_providers.clear();
 6369        self.available_code_actions.take();
 6370    }
 6371
 6372    pub fn add_code_action_provider(
 6373        &mut self,
 6374        provider: Rc<dyn CodeActionProvider>,
 6375        window: &mut Window,
 6376        cx: &mut Context<Self>,
 6377    ) {
 6378        if self
 6379            .code_action_providers
 6380            .iter()
 6381            .any(|existing_provider| existing_provider.id() == provider.id())
 6382        {
 6383            return;
 6384        }
 6385
 6386        self.code_action_providers.push(provider);
 6387        self.refresh_code_actions(window, cx);
 6388    }
 6389
 6390    pub fn remove_code_action_provider(
 6391        &mut self,
 6392        id: Arc<str>,
 6393        window: &mut Window,
 6394        cx: &mut Context<Self>,
 6395    ) {
 6396        self.code_action_providers
 6397            .retain(|provider| provider.id() != id);
 6398        self.refresh_code_actions(window, cx);
 6399    }
 6400
 6401    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6402        !self.code_action_providers.is_empty()
 6403            && EditorSettings::get_global(cx).toolbar.code_actions
 6404    }
 6405
 6406    pub fn has_available_code_actions(&self) -> bool {
 6407        self.available_code_actions
 6408            .as_ref()
 6409            .is_some_and(|(_, actions)| !actions.is_empty())
 6410    }
 6411
 6412    fn render_inline_code_actions(
 6413        &self,
 6414        icon_size: ui::IconSize,
 6415        display_row: DisplayRow,
 6416        is_active: bool,
 6417        cx: &mut Context<Self>,
 6418    ) -> AnyElement {
 6419        let show_tooltip = !self.context_menu_visible();
 6420        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6421            .icon_size(icon_size)
 6422            .shape(ui::IconButtonShape::Square)
 6423            .icon_color(ui::Color::Hidden)
 6424            .toggle_state(is_active)
 6425            .when(show_tooltip, |this| {
 6426                this.tooltip({
 6427                    let focus_handle = self.focus_handle.clone();
 6428                    move |window, cx| {
 6429                        Tooltip::for_action_in(
 6430                            "Toggle Code Actions",
 6431                            &ToggleCodeActions {
 6432                                deployed_from: None,
 6433                                quick_launch: false,
 6434                            },
 6435                            &focus_handle,
 6436                            window,
 6437                            cx,
 6438                        )
 6439                    }
 6440                })
 6441            })
 6442            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6443                window.focus(&editor.focus_handle(cx));
 6444                editor.toggle_code_actions(
 6445                    &crate::actions::ToggleCodeActions {
 6446                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6447                            display_row,
 6448                        )),
 6449                        quick_launch: false,
 6450                    },
 6451                    window,
 6452                    cx,
 6453                );
 6454            }))
 6455            .into_any_element()
 6456    }
 6457
 6458    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6459        &self.context_menu
 6460    }
 6461
 6462    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6463        let newest_selection = self.selections.newest_anchor().clone();
 6464        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6465        let buffer = self.buffer.read(cx);
 6466        if newest_selection.head().diff_base_anchor.is_some() {
 6467            return None;
 6468        }
 6469        let (start_buffer, start) =
 6470            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6471        let (end_buffer, end) =
 6472            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6473        if start_buffer != end_buffer {
 6474            return None;
 6475        }
 6476
 6477        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6478            cx.background_executor()
 6479                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6480                .await;
 6481
 6482            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6483                let providers = this.code_action_providers.clone();
 6484                let tasks = this
 6485                    .code_action_providers
 6486                    .iter()
 6487                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6488                    .collect::<Vec<_>>();
 6489                (providers, tasks)
 6490            })?;
 6491
 6492            let mut actions = Vec::new();
 6493            for (provider, provider_actions) in
 6494                providers.into_iter().zip(future::join_all(tasks).await)
 6495            {
 6496                if let Some(provider_actions) = provider_actions.log_err() {
 6497                    actions.extend(provider_actions.into_iter().map(|action| {
 6498                        AvailableCodeAction {
 6499                            excerpt_id: newest_selection.start.excerpt_id,
 6500                            action,
 6501                            provider: provider.clone(),
 6502                        }
 6503                    }));
 6504                }
 6505            }
 6506
 6507            this.update(cx, |this, cx| {
 6508                this.available_code_actions = if actions.is_empty() {
 6509                    None
 6510                } else {
 6511                    Some((
 6512                        Location {
 6513                            buffer: start_buffer,
 6514                            range: start..end,
 6515                        },
 6516                        actions.into(),
 6517                    ))
 6518                };
 6519                cx.notify();
 6520            })
 6521        }));
 6522        None
 6523    }
 6524
 6525    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6526        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6527            self.show_git_blame_inline = false;
 6528
 6529            self.show_git_blame_inline_delay_task =
 6530                Some(cx.spawn_in(window, async move |this, cx| {
 6531                    cx.background_executor().timer(delay).await;
 6532
 6533                    this.update(cx, |this, cx| {
 6534                        this.show_git_blame_inline = true;
 6535                        cx.notify();
 6536                    })
 6537                    .log_err();
 6538                }));
 6539        }
 6540    }
 6541
 6542    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6543        let snapshot = self.snapshot(window, cx);
 6544        let cursor = self.selections.newest::<Point>(cx).head();
 6545        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6546        else {
 6547            return;
 6548        };
 6549
 6550        let Some(blame) = self.blame.as_ref() else {
 6551            return;
 6552        };
 6553
 6554        let row_info = RowInfo {
 6555            buffer_id: Some(buffer.remote_id()),
 6556            buffer_row: Some(point.row),
 6557            ..Default::default()
 6558        };
 6559        let Some(blame_entry) = blame
 6560            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6561            .flatten()
 6562        else {
 6563            return;
 6564        };
 6565
 6566        let anchor = self.selections.newest_anchor().head();
 6567        let position = self.to_pixel_point(anchor, &snapshot, window);
 6568        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6569            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6570        };
 6571    }
 6572
 6573    fn show_blame_popover(
 6574        &mut self,
 6575        blame_entry: &BlameEntry,
 6576        position: gpui::Point<Pixels>,
 6577        ignore_timeout: bool,
 6578        cx: &mut Context<Self>,
 6579    ) {
 6580        if let Some(state) = &mut self.inline_blame_popover {
 6581            state.hide_task.take();
 6582        } else {
 6583            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6584            let blame_entry = blame_entry.clone();
 6585            let show_task = cx.spawn(async move |editor, cx| {
 6586                if !ignore_timeout {
 6587                    cx.background_executor()
 6588                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6589                        .await;
 6590                }
 6591                editor
 6592                    .update(cx, |editor, cx| {
 6593                        editor.inline_blame_popover_show_task.take();
 6594                        let Some(blame) = editor.blame.as_ref() else {
 6595                            return;
 6596                        };
 6597                        let blame = blame.read(cx);
 6598                        let details = blame.details_for_entry(&blame_entry);
 6599                        let markdown = cx.new(|cx| {
 6600                            Markdown::new(
 6601                                details
 6602                                    .as_ref()
 6603                                    .map(|message| message.message.clone())
 6604                                    .unwrap_or_default(),
 6605                                None,
 6606                                None,
 6607                                cx,
 6608                            )
 6609                        });
 6610                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6611                            position,
 6612                            hide_task: None,
 6613                            popover_bounds: None,
 6614                            popover_state: InlineBlamePopoverState {
 6615                                scroll_handle: ScrollHandle::new(),
 6616                                commit_message: details,
 6617                                markdown,
 6618                            },
 6619                            keyboard_grace: ignore_timeout,
 6620                        });
 6621                        cx.notify();
 6622                    })
 6623                    .ok();
 6624            });
 6625            self.inline_blame_popover_show_task = Some(show_task);
 6626        }
 6627    }
 6628
 6629    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6630        self.inline_blame_popover_show_task.take();
 6631        if let Some(state) = &mut self.inline_blame_popover {
 6632            let hide_task = cx.spawn(async move |editor, cx| {
 6633                cx.background_executor()
 6634                    .timer(std::time::Duration::from_millis(100))
 6635                    .await;
 6636                editor
 6637                    .update(cx, |editor, cx| {
 6638                        editor.inline_blame_popover.take();
 6639                        cx.notify();
 6640                    })
 6641                    .ok();
 6642            });
 6643            state.hide_task = Some(hide_task);
 6644        }
 6645    }
 6646
 6647    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6648        if self.pending_rename.is_some() {
 6649            return None;
 6650        }
 6651
 6652        let provider = self.semantics_provider.clone()?;
 6653        let buffer = self.buffer.read(cx);
 6654        let newest_selection = self.selections.newest_anchor().clone();
 6655        let cursor_position = newest_selection.head();
 6656        let (cursor_buffer, cursor_buffer_position) =
 6657            buffer.text_anchor_for_position(cursor_position, cx)?;
 6658        let (tail_buffer, tail_buffer_position) =
 6659            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6660        if cursor_buffer != tail_buffer {
 6661            return None;
 6662        }
 6663
 6664        let snapshot = cursor_buffer.read(cx).snapshot();
 6665        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6666        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6667        if start_word_range != end_word_range {
 6668            self.document_highlights_task.take();
 6669            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6670            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6671            return None;
 6672        }
 6673
 6674        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6675        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6676            cx.background_executor()
 6677                .timer(Duration::from_millis(debounce))
 6678                .await;
 6679
 6680            let highlights = if let Some(highlights) = cx
 6681                .update(|cx| {
 6682                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6683                })
 6684                .ok()
 6685                .flatten()
 6686            {
 6687                highlights.await.log_err()
 6688            } else {
 6689                None
 6690            };
 6691
 6692            if let Some(highlights) = highlights {
 6693                this.update(cx, |this, cx| {
 6694                    if this.pending_rename.is_some() {
 6695                        return;
 6696                    }
 6697
 6698                    let buffer = this.buffer.read(cx);
 6699                    if buffer
 6700                        .text_anchor_for_position(cursor_position, cx)
 6701                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6702                    {
 6703                        return;
 6704                    }
 6705
 6706                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6707                    let mut write_ranges = Vec::new();
 6708                    let mut read_ranges = Vec::new();
 6709                    for highlight in highlights {
 6710                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6711                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6712                        {
 6713                            let start = highlight
 6714                                .range
 6715                                .start
 6716                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6717                            let end = highlight
 6718                                .range
 6719                                .end
 6720                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6721                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6722                                continue;
 6723                            }
 6724
 6725                            let range = Anchor {
 6726                                buffer_id: Some(buffer_id),
 6727                                excerpt_id,
 6728                                text_anchor: start,
 6729                                diff_base_anchor: None,
 6730                            }..Anchor {
 6731                                buffer_id: Some(buffer_id),
 6732                                excerpt_id,
 6733                                text_anchor: end,
 6734                                diff_base_anchor: None,
 6735                            };
 6736                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6737                                write_ranges.push(range);
 6738                            } else {
 6739                                read_ranges.push(range);
 6740                            }
 6741                        }
 6742                    }
 6743
 6744                    this.highlight_background::<DocumentHighlightRead>(
 6745                        &read_ranges,
 6746                        |theme| theme.colors().editor_document_highlight_read_background,
 6747                        cx,
 6748                    );
 6749                    this.highlight_background::<DocumentHighlightWrite>(
 6750                        &write_ranges,
 6751                        |theme| theme.colors().editor_document_highlight_write_background,
 6752                        cx,
 6753                    );
 6754                    cx.notify();
 6755                })
 6756                .log_err();
 6757            }
 6758        }));
 6759        None
 6760    }
 6761
 6762    fn prepare_highlight_query_from_selection(
 6763        &mut self,
 6764        cx: &mut Context<Editor>,
 6765    ) -> Option<(String, Range<Anchor>)> {
 6766        if matches!(self.mode, EditorMode::SingleLine) {
 6767            return None;
 6768        }
 6769        if !EditorSettings::get_global(cx).selection_highlight {
 6770            return None;
 6771        }
 6772        if self.selections.count() != 1 || self.selections.line_mode {
 6773            return None;
 6774        }
 6775        let selection = self.selections.newest::<Point>(cx);
 6776        if selection.is_empty() || selection.start.row != selection.end.row {
 6777            return None;
 6778        }
 6779        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6780        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6781        let query = multi_buffer_snapshot
 6782            .text_for_range(selection_anchor_range.clone())
 6783            .collect::<String>();
 6784        if query.trim().is_empty() {
 6785            return None;
 6786        }
 6787        Some((query, selection_anchor_range))
 6788    }
 6789
 6790    fn update_selection_occurrence_highlights(
 6791        &mut self,
 6792        query_text: String,
 6793        query_range: Range<Anchor>,
 6794        multi_buffer_range_to_query: Range<Point>,
 6795        use_debounce: bool,
 6796        window: &mut Window,
 6797        cx: &mut Context<Editor>,
 6798    ) -> Task<()> {
 6799        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6800        cx.spawn_in(window, async move |editor, cx| {
 6801            if use_debounce {
 6802                cx.background_executor()
 6803                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6804                    .await;
 6805            }
 6806            let match_task = cx.background_spawn(async move {
 6807                let buffer_ranges = multi_buffer_snapshot
 6808                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6809                    .into_iter()
 6810                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6811                let mut match_ranges = Vec::new();
 6812                let Ok(regex) = project::search::SearchQuery::text(
 6813                    query_text.clone(),
 6814                    false,
 6815                    false,
 6816                    false,
 6817                    Default::default(),
 6818                    Default::default(),
 6819                    false,
 6820                    None,
 6821                ) else {
 6822                    return Vec::default();
 6823                };
 6824                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6825                    match_ranges.extend(
 6826                        regex
 6827                            .search(buffer_snapshot, Some(search_range.clone()))
 6828                            .await
 6829                            .into_iter()
 6830                            .filter_map(|match_range| {
 6831                                let match_start = buffer_snapshot
 6832                                    .anchor_after(search_range.start + match_range.start);
 6833                                let match_end = buffer_snapshot
 6834                                    .anchor_before(search_range.start + match_range.end);
 6835                                let match_anchor_range = Anchor::range_in_buffer(
 6836                                    excerpt_id,
 6837                                    buffer_snapshot.remote_id(),
 6838                                    match_start..match_end,
 6839                                );
 6840                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6841                            }),
 6842                    );
 6843                }
 6844                match_ranges
 6845            });
 6846            let match_ranges = match_task.await;
 6847            editor
 6848                .update_in(cx, |editor, _, cx| {
 6849                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6850                    if !match_ranges.is_empty() {
 6851                        editor.highlight_background::<SelectedTextHighlight>(
 6852                            &match_ranges,
 6853                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6854                            cx,
 6855                        )
 6856                    }
 6857                })
 6858                .log_err();
 6859        })
 6860    }
 6861
 6862    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6863        struct NewlineFold;
 6864        let type_id = std::any::TypeId::of::<NewlineFold>();
 6865        if !self.mode.is_single_line() {
 6866            return;
 6867        }
 6868        let snapshot = self.snapshot(window, cx);
 6869        if snapshot.buffer_snapshot.max_point().row == 0 {
 6870            return;
 6871        }
 6872        let task = cx.background_spawn(async move {
 6873            let new_newlines = snapshot
 6874                .buffer_chars_at(0)
 6875                .filter_map(|(c, i)| {
 6876                    if c == '\n' {
 6877                        Some(
 6878                            snapshot.buffer_snapshot.anchor_after(i)
 6879                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6880                        )
 6881                    } else {
 6882                        None
 6883                    }
 6884                })
 6885                .collect::<Vec<_>>();
 6886            let existing_newlines = snapshot
 6887                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6888                .filter_map(|fold| {
 6889                    if fold.placeholder.type_tag == Some(type_id) {
 6890                        Some(fold.range.start..fold.range.end)
 6891                    } else {
 6892                        None
 6893                    }
 6894                })
 6895                .collect::<Vec<_>>();
 6896
 6897            (new_newlines, existing_newlines)
 6898        });
 6899        self.folding_newlines = cx.spawn(async move |this, cx| {
 6900            let (new_newlines, existing_newlines) = task.await;
 6901            if new_newlines == existing_newlines {
 6902                return;
 6903            }
 6904            let placeholder = FoldPlaceholder {
 6905                render: Arc::new(move |_, _, cx| {
 6906                    div()
 6907                        .bg(cx.theme().status().hint_background)
 6908                        .border_b_1()
 6909                        .size_full()
 6910                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6911                        .border_color(cx.theme().status().hint)
 6912                        .child("\\n")
 6913                        .into_any()
 6914                }),
 6915                constrain_width: false,
 6916                merge_adjacent: false,
 6917                type_tag: Some(type_id),
 6918            };
 6919            let creases = new_newlines
 6920                .into_iter()
 6921                .map(|range| Crease::simple(range, placeholder.clone()))
 6922                .collect();
 6923            this.update(cx, |this, cx| {
 6924                this.display_map.update(cx, |display_map, cx| {
 6925                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6926                    display_map.fold(creases, cx);
 6927                });
 6928            })
 6929            .ok();
 6930        });
 6931    }
 6932
 6933    fn refresh_selected_text_highlights(
 6934        &mut self,
 6935        on_buffer_edit: bool,
 6936        window: &mut Window,
 6937        cx: &mut Context<Editor>,
 6938    ) {
 6939        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6940        else {
 6941            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6942            self.quick_selection_highlight_task.take();
 6943            self.debounced_selection_highlight_task.take();
 6944            return;
 6945        };
 6946        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6947        if on_buffer_edit
 6948            || self
 6949                .quick_selection_highlight_task
 6950                .as_ref()
 6951                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6952        {
 6953            let multi_buffer_visible_start = self
 6954                .scroll_manager
 6955                .anchor()
 6956                .anchor
 6957                .to_point(&multi_buffer_snapshot);
 6958            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6959                multi_buffer_visible_start
 6960                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6961                Bias::Left,
 6962            );
 6963            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6964            self.quick_selection_highlight_task = Some((
 6965                query_range.clone(),
 6966                self.update_selection_occurrence_highlights(
 6967                    query_text.clone(),
 6968                    query_range.clone(),
 6969                    multi_buffer_visible_range,
 6970                    false,
 6971                    window,
 6972                    cx,
 6973                ),
 6974            ));
 6975        }
 6976        if on_buffer_edit
 6977            || self
 6978                .debounced_selection_highlight_task
 6979                .as_ref()
 6980                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6981        {
 6982            let multi_buffer_start = multi_buffer_snapshot
 6983                .anchor_before(0)
 6984                .to_point(&multi_buffer_snapshot);
 6985            let multi_buffer_end = multi_buffer_snapshot
 6986                .anchor_after(multi_buffer_snapshot.len())
 6987                .to_point(&multi_buffer_snapshot);
 6988            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6989            self.debounced_selection_highlight_task = Some((
 6990                query_range.clone(),
 6991                self.update_selection_occurrence_highlights(
 6992                    query_text,
 6993                    query_range,
 6994                    multi_buffer_full_range,
 6995                    true,
 6996                    window,
 6997                    cx,
 6998                ),
 6999            ));
 7000        }
 7001    }
 7002
 7003    pub fn refresh_edit_prediction(
 7004        &mut self,
 7005        debounce: bool,
 7006        user_requested: bool,
 7007        window: &mut Window,
 7008        cx: &mut Context<Self>,
 7009    ) -> Option<()> {
 7010        if DisableAiSettings::get_global(cx).disable_ai {
 7011            return None;
 7012        }
 7013
 7014        let provider = self.edit_prediction_provider()?;
 7015        let cursor = self.selections.newest_anchor().head();
 7016        let (buffer, cursor_buffer_position) =
 7017            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7018
 7019        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7020            self.discard_edit_prediction(false, cx);
 7021            return None;
 7022        }
 7023
 7024        if !user_requested
 7025            && (!self.should_show_edit_predictions()
 7026                || !self.is_focused(window)
 7027                || buffer.read(cx).is_empty())
 7028        {
 7029            self.discard_edit_prediction(false, cx);
 7030            return None;
 7031        }
 7032
 7033        self.update_visible_edit_prediction(window, cx);
 7034        provider.refresh(
 7035            self.project.clone(),
 7036            buffer,
 7037            cursor_buffer_position,
 7038            debounce,
 7039            cx,
 7040        );
 7041        Some(())
 7042    }
 7043
 7044    fn show_edit_predictions_in_menu(&self) -> bool {
 7045        match self.edit_prediction_settings {
 7046            EditPredictionSettings::Disabled => false,
 7047            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7048        }
 7049    }
 7050
 7051    pub fn edit_predictions_enabled(&self) -> bool {
 7052        match self.edit_prediction_settings {
 7053            EditPredictionSettings::Disabled => false,
 7054            EditPredictionSettings::Enabled { .. } => true,
 7055        }
 7056    }
 7057
 7058    fn edit_prediction_requires_modifier(&self) -> bool {
 7059        match self.edit_prediction_settings {
 7060            EditPredictionSettings::Disabled => false,
 7061            EditPredictionSettings::Enabled {
 7062                preview_requires_modifier,
 7063                ..
 7064            } => preview_requires_modifier,
 7065        }
 7066    }
 7067
 7068    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7069        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7070            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7071            self.discard_edit_prediction(false, cx);
 7072        } else {
 7073            let selection = self.selections.newest_anchor();
 7074            let cursor = selection.head();
 7075
 7076            if let Some((buffer, cursor_buffer_position)) =
 7077                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7078            {
 7079                self.edit_prediction_settings =
 7080                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7081            }
 7082        }
 7083    }
 7084
 7085    fn edit_prediction_settings_at_position(
 7086        &self,
 7087        buffer: &Entity<Buffer>,
 7088        buffer_position: language::Anchor,
 7089        cx: &App,
 7090    ) -> EditPredictionSettings {
 7091        if !self.mode.is_full()
 7092            || !self.show_edit_predictions_override.unwrap_or(true)
 7093            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7094        {
 7095            return EditPredictionSettings::Disabled;
 7096        }
 7097
 7098        let buffer = buffer.read(cx);
 7099
 7100        let file = buffer.file();
 7101
 7102        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7103            return EditPredictionSettings::Disabled;
 7104        };
 7105
 7106        let by_provider = matches!(
 7107            self.menu_edit_predictions_policy,
 7108            MenuEditPredictionsPolicy::ByProvider
 7109        );
 7110
 7111        let show_in_menu = by_provider
 7112            && self
 7113                .edit_prediction_provider
 7114                .as_ref()
 7115                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7116
 7117        let preview_requires_modifier =
 7118            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7119
 7120        EditPredictionSettings::Enabled {
 7121            show_in_menu,
 7122            preview_requires_modifier,
 7123        }
 7124    }
 7125
 7126    fn should_show_edit_predictions(&self) -> bool {
 7127        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7128    }
 7129
 7130    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7131        matches!(
 7132            self.edit_prediction_preview,
 7133            EditPredictionPreview::Active { .. }
 7134        )
 7135    }
 7136
 7137    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7138        let cursor = self.selections.newest_anchor().head();
 7139        if let Some((buffer, cursor_position)) =
 7140            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7141        {
 7142            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7143        } else {
 7144            false
 7145        }
 7146    }
 7147
 7148    pub fn supports_minimap(&self, cx: &App) -> bool {
 7149        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7150    }
 7151
 7152    fn edit_predictions_enabled_in_buffer(
 7153        &self,
 7154        buffer: &Entity<Buffer>,
 7155        buffer_position: language::Anchor,
 7156        cx: &App,
 7157    ) -> bool {
 7158        maybe!({
 7159            if self.read_only(cx) {
 7160                return Some(false);
 7161            }
 7162            let provider = self.edit_prediction_provider()?;
 7163            if !provider.is_enabled(buffer, buffer_position, cx) {
 7164                return Some(false);
 7165            }
 7166            let buffer = buffer.read(cx);
 7167            let Some(file) = buffer.file() else {
 7168                return Some(true);
 7169            };
 7170            let settings = all_language_settings(Some(file), cx);
 7171            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7172        })
 7173        .unwrap_or(false)
 7174    }
 7175
 7176    fn cycle_edit_prediction(
 7177        &mut self,
 7178        direction: Direction,
 7179        window: &mut Window,
 7180        cx: &mut Context<Self>,
 7181    ) -> Option<()> {
 7182        let provider = self.edit_prediction_provider()?;
 7183        let cursor = self.selections.newest_anchor().head();
 7184        let (buffer, cursor_buffer_position) =
 7185            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7186        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7187            return None;
 7188        }
 7189
 7190        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7191        self.update_visible_edit_prediction(window, cx);
 7192
 7193        Some(())
 7194    }
 7195
 7196    pub fn show_edit_prediction(
 7197        &mut self,
 7198        _: &ShowEditPrediction,
 7199        window: &mut Window,
 7200        cx: &mut Context<Self>,
 7201    ) {
 7202        if !self.has_active_edit_prediction() {
 7203            self.refresh_edit_prediction(false, true, window, cx);
 7204            return;
 7205        }
 7206
 7207        self.update_visible_edit_prediction(window, cx);
 7208    }
 7209
 7210    pub fn display_cursor_names(
 7211        &mut self,
 7212        _: &DisplayCursorNames,
 7213        window: &mut Window,
 7214        cx: &mut Context<Self>,
 7215    ) {
 7216        self.show_cursor_names(window, cx);
 7217    }
 7218
 7219    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7220        self.show_cursor_names = true;
 7221        cx.notify();
 7222        cx.spawn_in(window, async move |this, cx| {
 7223            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7224            this.update(cx, |this, cx| {
 7225                this.show_cursor_names = false;
 7226                cx.notify()
 7227            })
 7228            .ok()
 7229        })
 7230        .detach();
 7231    }
 7232
 7233    pub fn next_edit_prediction(
 7234        &mut self,
 7235        _: &NextEditPrediction,
 7236        window: &mut Window,
 7237        cx: &mut Context<Self>,
 7238    ) {
 7239        if self.has_active_edit_prediction() {
 7240            self.cycle_edit_prediction(Direction::Next, window, cx);
 7241        } else {
 7242            let is_copilot_disabled = self
 7243                .refresh_edit_prediction(false, true, window, cx)
 7244                .is_none();
 7245            if is_copilot_disabled {
 7246                cx.propagate();
 7247            }
 7248        }
 7249    }
 7250
 7251    pub fn previous_edit_prediction(
 7252        &mut self,
 7253        _: &PreviousEditPrediction,
 7254        window: &mut Window,
 7255        cx: &mut Context<Self>,
 7256    ) {
 7257        if self.has_active_edit_prediction() {
 7258            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7259        } else {
 7260            let is_copilot_disabled = self
 7261                .refresh_edit_prediction(false, true, window, cx)
 7262                .is_none();
 7263            if is_copilot_disabled {
 7264                cx.propagate();
 7265            }
 7266        }
 7267    }
 7268
 7269    pub fn accept_edit_prediction(
 7270        &mut self,
 7271        _: &AcceptEditPrediction,
 7272        window: &mut Window,
 7273        cx: &mut Context<Self>,
 7274    ) {
 7275        if self.show_edit_predictions_in_menu() {
 7276            self.hide_context_menu(window, cx);
 7277        }
 7278
 7279        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7280            return;
 7281        };
 7282
 7283        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7284
 7285        match &active_edit_prediction.completion {
 7286            EditPrediction::Move { target, .. } => {
 7287                let target = *target;
 7288
 7289                if let Some(position_map) = &self.last_position_map {
 7290                    if position_map
 7291                        .visible_row_range
 7292                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7293                        || !self.edit_prediction_requires_modifier()
 7294                    {
 7295                        self.unfold_ranges(&[target..target], true, false, cx);
 7296                        // Note that this is also done in vim's handler of the Tab action.
 7297                        self.change_selections(
 7298                            SelectionEffects::scroll(Autoscroll::newest()),
 7299                            window,
 7300                            cx,
 7301                            |selections| {
 7302                                selections.select_anchor_ranges([target..target]);
 7303                            },
 7304                        );
 7305                        self.clear_row_highlights::<EditPredictionPreview>();
 7306
 7307                        self.edit_prediction_preview
 7308                            .set_previous_scroll_position(None);
 7309                    } else {
 7310                        self.edit_prediction_preview
 7311                            .set_previous_scroll_position(Some(
 7312                                position_map.snapshot.scroll_anchor,
 7313                            ));
 7314
 7315                        self.highlight_rows::<EditPredictionPreview>(
 7316                            target..target,
 7317                            cx.theme().colors().editor_highlighted_line_background,
 7318                            RowHighlightOptions {
 7319                                autoscroll: true,
 7320                                ..Default::default()
 7321                            },
 7322                            cx,
 7323                        );
 7324                        self.request_autoscroll(Autoscroll::fit(), cx);
 7325                    }
 7326                }
 7327            }
 7328            EditPrediction::Edit { edits, .. } => {
 7329                if let Some(provider) = self.edit_prediction_provider() {
 7330                    provider.accept(cx);
 7331                }
 7332
 7333                // Store the transaction ID and selections before applying the edit
 7334                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7335
 7336                let snapshot = self.buffer.read(cx).snapshot(cx);
 7337                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7338
 7339                self.buffer.update(cx, |buffer, cx| {
 7340                    buffer.edit(edits.iter().cloned(), None, cx)
 7341                });
 7342
 7343                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7344                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7345                });
 7346
 7347                let selections = self.selections.disjoint_anchors();
 7348                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7349                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7350                    if has_new_transaction {
 7351                        self.selection_history
 7352                            .insert_transaction(transaction_id_now, selections);
 7353                    }
 7354                }
 7355
 7356                self.update_visible_edit_prediction(window, cx);
 7357                if self.active_edit_prediction.is_none() {
 7358                    self.refresh_edit_prediction(true, true, window, cx);
 7359                }
 7360
 7361                cx.notify();
 7362            }
 7363        }
 7364
 7365        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7366    }
 7367
 7368    pub fn accept_partial_edit_prediction(
 7369        &mut self,
 7370        _: &AcceptPartialEditPrediction,
 7371        window: &mut Window,
 7372        cx: &mut Context<Self>,
 7373    ) {
 7374        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7375            return;
 7376        };
 7377        if self.selections.count() != 1 {
 7378            return;
 7379        }
 7380
 7381        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7382
 7383        match &active_edit_prediction.completion {
 7384            EditPrediction::Move { target, .. } => {
 7385                let target = *target;
 7386                self.change_selections(
 7387                    SelectionEffects::scroll(Autoscroll::newest()),
 7388                    window,
 7389                    cx,
 7390                    |selections| {
 7391                        selections.select_anchor_ranges([target..target]);
 7392                    },
 7393                );
 7394            }
 7395            EditPrediction::Edit { edits, .. } => {
 7396                // Find an insertion that starts at the cursor position.
 7397                let snapshot = self.buffer.read(cx).snapshot(cx);
 7398                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7399                let insertion = edits.iter().find_map(|(range, text)| {
 7400                    let range = range.to_offset(&snapshot);
 7401                    if range.is_empty() && range.start == cursor_offset {
 7402                        Some(text)
 7403                    } else {
 7404                        None
 7405                    }
 7406                });
 7407
 7408                if let Some(text) = insertion {
 7409                    let mut partial_completion = text
 7410                        .chars()
 7411                        .by_ref()
 7412                        .take_while(|c| c.is_alphabetic())
 7413                        .collect::<String>();
 7414                    if partial_completion.is_empty() {
 7415                        partial_completion = text
 7416                            .chars()
 7417                            .by_ref()
 7418                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7419                            .collect::<String>();
 7420                    }
 7421
 7422                    cx.emit(EditorEvent::InputHandled {
 7423                        utf16_range_to_replace: None,
 7424                        text: partial_completion.clone().into(),
 7425                    });
 7426
 7427                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7428
 7429                    self.refresh_edit_prediction(true, true, window, cx);
 7430                    cx.notify();
 7431                } else {
 7432                    self.accept_edit_prediction(&Default::default(), window, cx);
 7433                }
 7434            }
 7435        }
 7436    }
 7437
 7438    fn discard_edit_prediction(
 7439        &mut self,
 7440        should_report_edit_prediction_event: bool,
 7441        cx: &mut Context<Self>,
 7442    ) -> bool {
 7443        if should_report_edit_prediction_event {
 7444            let completion_id = self
 7445                .active_edit_prediction
 7446                .as_ref()
 7447                .and_then(|active_completion| active_completion.completion_id.clone());
 7448
 7449            self.report_edit_prediction_event(completion_id, false, cx);
 7450        }
 7451
 7452        if let Some(provider) = self.edit_prediction_provider() {
 7453            provider.discard(cx);
 7454        }
 7455
 7456        self.take_active_edit_prediction(cx)
 7457    }
 7458
 7459    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7460        let Some(provider) = self.edit_prediction_provider() else {
 7461            return;
 7462        };
 7463
 7464        let Some((_, buffer, _)) = self
 7465            .buffer
 7466            .read(cx)
 7467            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7468        else {
 7469            return;
 7470        };
 7471
 7472        let extension = buffer
 7473            .read(cx)
 7474            .file()
 7475            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7476
 7477        let event_type = match accepted {
 7478            true => "Edit Prediction Accepted",
 7479            false => "Edit Prediction Discarded",
 7480        };
 7481        telemetry::event!(
 7482            event_type,
 7483            provider = provider.name(),
 7484            prediction_id = id,
 7485            suggestion_accepted = accepted,
 7486            file_extension = extension,
 7487        );
 7488    }
 7489
 7490    pub fn has_active_edit_prediction(&self) -> bool {
 7491        self.active_edit_prediction.is_some()
 7492    }
 7493
 7494    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7495        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7496            return false;
 7497        };
 7498
 7499        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7500        self.clear_highlights::<EditPredictionHighlight>(cx);
 7501        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7502        true
 7503    }
 7504
 7505    /// Returns true when we're displaying the edit prediction popover below the cursor
 7506    /// like we are not previewing and the LSP autocomplete menu is visible
 7507    /// or we are in `when_holding_modifier` mode.
 7508    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7509        if self.edit_prediction_preview_is_active()
 7510            || !self.show_edit_predictions_in_menu()
 7511            || !self.edit_predictions_enabled()
 7512        {
 7513            return false;
 7514        }
 7515
 7516        if self.has_visible_completions_menu() {
 7517            return true;
 7518        }
 7519
 7520        has_completion && self.edit_prediction_requires_modifier()
 7521    }
 7522
 7523    fn handle_modifiers_changed(
 7524        &mut self,
 7525        modifiers: Modifiers,
 7526        position_map: &PositionMap,
 7527        window: &mut Window,
 7528        cx: &mut Context<Self>,
 7529    ) {
 7530        if self.show_edit_predictions_in_menu() {
 7531            self.update_edit_prediction_preview(&modifiers, window, cx);
 7532        }
 7533
 7534        self.update_selection_mode(&modifiers, position_map, window, cx);
 7535
 7536        let mouse_position = window.mouse_position();
 7537        if !position_map.text_hitbox.is_hovered(window) {
 7538            return;
 7539        }
 7540
 7541        self.update_hovered_link(
 7542            position_map.point_for_position(mouse_position),
 7543            &position_map.snapshot,
 7544            modifiers,
 7545            window,
 7546            cx,
 7547        )
 7548    }
 7549
 7550    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7551        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7552        if invert {
 7553            match multi_cursor_setting {
 7554                MultiCursorModifier::Alt => modifiers.alt,
 7555                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7556            }
 7557        } else {
 7558            match multi_cursor_setting {
 7559                MultiCursorModifier::Alt => modifiers.secondary(),
 7560                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7561            }
 7562        }
 7563    }
 7564
 7565    fn columnar_selection_mode(
 7566        modifiers: &Modifiers,
 7567        cx: &mut Context<Self>,
 7568    ) -> Option<ColumnarMode> {
 7569        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7570            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7571                Some(ColumnarMode::FromMouse)
 7572            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7573                Some(ColumnarMode::FromSelection)
 7574            } else {
 7575                None
 7576            }
 7577        } else {
 7578            None
 7579        }
 7580    }
 7581
 7582    fn update_selection_mode(
 7583        &mut self,
 7584        modifiers: &Modifiers,
 7585        position_map: &PositionMap,
 7586        window: &mut Window,
 7587        cx: &mut Context<Self>,
 7588    ) {
 7589        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7590            return;
 7591        };
 7592        if self.selections.pending.is_none() {
 7593            return;
 7594        }
 7595
 7596        let mouse_position = window.mouse_position();
 7597        let point_for_position = position_map.point_for_position(mouse_position);
 7598        let position = point_for_position.previous_valid;
 7599
 7600        self.select(
 7601            SelectPhase::BeginColumnar {
 7602                position,
 7603                reset: false,
 7604                mode,
 7605                goal_column: point_for_position.exact_unclipped.column(),
 7606            },
 7607            window,
 7608            cx,
 7609        );
 7610    }
 7611
 7612    fn update_edit_prediction_preview(
 7613        &mut self,
 7614        modifiers: &Modifiers,
 7615        window: &mut Window,
 7616        cx: &mut Context<Self>,
 7617    ) {
 7618        let mut modifiers_held = false;
 7619        if let Some(accept_keystroke) = self
 7620            .accept_edit_prediction_keybind(false, window, cx)
 7621            .keystroke()
 7622        {
 7623            modifiers_held = modifiers_held
 7624                || (&accept_keystroke.modifiers == modifiers
 7625                    && accept_keystroke.modifiers.modified());
 7626        };
 7627        if let Some(accept_partial_keystroke) = self
 7628            .accept_edit_prediction_keybind(true, window, cx)
 7629            .keystroke()
 7630        {
 7631            modifiers_held = modifiers_held
 7632                || (&accept_partial_keystroke.modifiers == modifiers
 7633                    && accept_partial_keystroke.modifiers.modified());
 7634        }
 7635
 7636        if modifiers_held {
 7637            if matches!(
 7638                self.edit_prediction_preview,
 7639                EditPredictionPreview::Inactive { .. }
 7640            ) {
 7641                self.edit_prediction_preview = EditPredictionPreview::Active {
 7642                    previous_scroll_position: None,
 7643                    since: Instant::now(),
 7644                };
 7645
 7646                self.update_visible_edit_prediction(window, cx);
 7647                cx.notify();
 7648            }
 7649        } else if let EditPredictionPreview::Active {
 7650            previous_scroll_position,
 7651            since,
 7652        } = self.edit_prediction_preview
 7653        {
 7654            if let (Some(previous_scroll_position), Some(position_map)) =
 7655                (previous_scroll_position, self.last_position_map.as_ref())
 7656            {
 7657                self.set_scroll_position(
 7658                    previous_scroll_position
 7659                        .scroll_position(&position_map.snapshot.display_snapshot),
 7660                    window,
 7661                    cx,
 7662                );
 7663            }
 7664
 7665            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7666                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7667            };
 7668            self.clear_row_highlights::<EditPredictionPreview>();
 7669            self.update_visible_edit_prediction(window, cx);
 7670            cx.notify();
 7671        }
 7672    }
 7673
 7674    fn update_visible_edit_prediction(
 7675        &mut self,
 7676        _window: &mut Window,
 7677        cx: &mut Context<Self>,
 7678    ) -> Option<()> {
 7679        if DisableAiSettings::get_global(cx).disable_ai {
 7680            return None;
 7681        }
 7682
 7683        let selection = self.selections.newest_anchor();
 7684        let cursor = selection.head();
 7685        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7686        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7687        let excerpt_id = cursor.excerpt_id;
 7688
 7689        let show_in_menu = self.show_edit_predictions_in_menu();
 7690        let completions_menu_has_precedence = !show_in_menu
 7691            && (self.context_menu.borrow().is_some()
 7692                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7693
 7694        if completions_menu_has_precedence
 7695            || !offset_selection.is_empty()
 7696            || self
 7697                .active_edit_prediction
 7698                .as_ref()
 7699                .is_some_and(|completion| {
 7700                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7701                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7702                    !invalidation_range.contains(&offset_selection.head())
 7703                })
 7704        {
 7705            self.discard_edit_prediction(false, cx);
 7706            return None;
 7707        }
 7708
 7709        self.take_active_edit_prediction(cx);
 7710        let Some(provider) = self.edit_prediction_provider() else {
 7711            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7712            return None;
 7713        };
 7714
 7715        let (buffer, cursor_buffer_position) =
 7716            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7717
 7718        self.edit_prediction_settings =
 7719            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7720
 7721        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7722            self.discard_edit_prediction(false, cx);
 7723            return None;
 7724        };
 7725
 7726        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7727
 7728        if self.edit_prediction_indent_conflict {
 7729            let cursor_point = cursor.to_point(&multibuffer);
 7730
 7731            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7732
 7733            if let Some((_, indent)) = indents.iter().next()
 7734                && indent.len == cursor_point.column
 7735            {
 7736                self.edit_prediction_indent_conflict = false;
 7737            }
 7738        }
 7739
 7740        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7741        let edits = edit_prediction
 7742            .edits
 7743            .into_iter()
 7744            .flat_map(|(range, new_text)| {
 7745                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7746                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7747                Some((start..end, new_text))
 7748            })
 7749            .collect::<Vec<_>>();
 7750        if edits.is_empty() {
 7751            return None;
 7752        }
 7753
 7754        let first_edit_start = edits.first().unwrap().0.start;
 7755        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7756        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7757
 7758        let last_edit_end = edits.last().unwrap().0.end;
 7759        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7760        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7761
 7762        let cursor_row = cursor.to_point(&multibuffer).row;
 7763
 7764        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7765
 7766        let mut inlay_ids = Vec::new();
 7767        let invalidation_row_range;
 7768        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7769            Some(cursor_row..edit_end_row)
 7770        } else if cursor_row > edit_end_row {
 7771            Some(edit_start_row..cursor_row)
 7772        } else {
 7773            None
 7774        };
 7775        let supports_jump = self
 7776            .edit_prediction_provider
 7777            .as_ref()
 7778            .map(|provider| provider.provider.supports_jump_to_edit())
 7779            .unwrap_or(true);
 7780
 7781        let is_move = supports_jump
 7782            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7783        let completion = if is_move {
 7784            invalidation_row_range =
 7785                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7786            let target = first_edit_start;
 7787            EditPrediction::Move { target, snapshot }
 7788        } else {
 7789            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7790                && !self.edit_predictions_hidden_for_vim_mode;
 7791
 7792            if show_completions_in_buffer {
 7793                if edits
 7794                    .iter()
 7795                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7796                {
 7797                    let mut inlays = Vec::new();
 7798                    for (range, new_text) in &edits {
 7799                        let inlay = Inlay::edit_prediction(
 7800                            post_inc(&mut self.next_inlay_id),
 7801                            range.start,
 7802                            new_text.as_str(),
 7803                        );
 7804                        inlay_ids.push(inlay.id);
 7805                        inlays.push(inlay);
 7806                    }
 7807
 7808                    self.splice_inlays(&[], inlays, cx);
 7809                } else {
 7810                    let background_color = cx.theme().status().deleted_background;
 7811                    self.highlight_text::<EditPredictionHighlight>(
 7812                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7813                        HighlightStyle {
 7814                            background_color: Some(background_color),
 7815                            ..Default::default()
 7816                        },
 7817                        cx,
 7818                    );
 7819                }
 7820            }
 7821
 7822            invalidation_row_range = edit_start_row..edit_end_row;
 7823
 7824            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7825                if provider.show_tab_accept_marker() {
 7826                    EditDisplayMode::TabAccept
 7827                } else {
 7828                    EditDisplayMode::Inline
 7829                }
 7830            } else {
 7831                EditDisplayMode::DiffPopover
 7832            };
 7833
 7834            EditPrediction::Edit {
 7835                edits,
 7836                edit_preview: edit_prediction.edit_preview,
 7837                display_mode,
 7838                snapshot,
 7839            }
 7840        };
 7841
 7842        let invalidation_range = multibuffer
 7843            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7844            ..multibuffer.anchor_after(Point::new(
 7845                invalidation_row_range.end,
 7846                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7847            ));
 7848
 7849        self.stale_edit_prediction_in_menu = None;
 7850        self.active_edit_prediction = Some(EditPredictionState {
 7851            inlay_ids,
 7852            completion,
 7853            completion_id: edit_prediction.id,
 7854            invalidation_range,
 7855        });
 7856
 7857        cx.notify();
 7858
 7859        Some(())
 7860    }
 7861
 7862    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7863        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7864    }
 7865
 7866    fn clear_tasks(&mut self) {
 7867        self.tasks.clear()
 7868    }
 7869
 7870    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7871        if self.tasks.insert(key, value).is_some() {
 7872            // This case should hopefully be rare, but just in case...
 7873            log::error!(
 7874                "multiple different run targets found on a single line, only the last target will be rendered"
 7875            )
 7876        }
 7877    }
 7878
 7879    /// Get all display points of breakpoints that will be rendered within editor
 7880    ///
 7881    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7882    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7883    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7884    fn active_breakpoints(
 7885        &self,
 7886        range: Range<DisplayRow>,
 7887        window: &mut Window,
 7888        cx: &mut Context<Self>,
 7889    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7890        let mut breakpoint_display_points = HashMap::default();
 7891
 7892        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7893            return breakpoint_display_points;
 7894        };
 7895
 7896        let snapshot = self.snapshot(window, cx);
 7897
 7898        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7899        let Some(project) = self.project() else {
 7900            return breakpoint_display_points;
 7901        };
 7902
 7903        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7904            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7905
 7906        for (buffer_snapshot, range, excerpt_id) in
 7907            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7908        {
 7909            let Some(buffer) = project
 7910                .read(cx)
 7911                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7912            else {
 7913                continue;
 7914            };
 7915            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7916                &buffer,
 7917                Some(
 7918                    buffer_snapshot.anchor_before(range.start)
 7919                        ..buffer_snapshot.anchor_after(range.end),
 7920                ),
 7921                buffer_snapshot,
 7922                cx,
 7923            );
 7924            for (breakpoint, state) in breakpoints {
 7925                let multi_buffer_anchor =
 7926                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7927                let position = multi_buffer_anchor
 7928                    .to_point(multi_buffer_snapshot)
 7929                    .to_display_point(&snapshot);
 7930
 7931                breakpoint_display_points.insert(
 7932                    position.row(),
 7933                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7934                );
 7935            }
 7936        }
 7937
 7938        breakpoint_display_points
 7939    }
 7940
 7941    fn breakpoint_context_menu(
 7942        &self,
 7943        anchor: Anchor,
 7944        window: &mut Window,
 7945        cx: &mut Context<Self>,
 7946    ) -> Entity<ui::ContextMenu> {
 7947        let weak_editor = cx.weak_entity();
 7948        let focus_handle = self.focus_handle(cx);
 7949
 7950        let row = self
 7951            .buffer
 7952            .read(cx)
 7953            .snapshot(cx)
 7954            .summary_for_anchor::<Point>(&anchor)
 7955            .row;
 7956
 7957        let breakpoint = self
 7958            .breakpoint_at_row(row, window, cx)
 7959            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7960
 7961        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7962            "Edit Log Breakpoint"
 7963        } else {
 7964            "Set Log Breakpoint"
 7965        };
 7966
 7967        let condition_breakpoint_msg = if breakpoint
 7968            .as_ref()
 7969            .is_some_and(|bp| bp.1.condition.is_some())
 7970        {
 7971            "Edit Condition Breakpoint"
 7972        } else {
 7973            "Set Condition Breakpoint"
 7974        };
 7975
 7976        let hit_condition_breakpoint_msg = if breakpoint
 7977            .as_ref()
 7978            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7979        {
 7980            "Edit Hit Condition Breakpoint"
 7981        } else {
 7982            "Set Hit Condition Breakpoint"
 7983        };
 7984
 7985        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7986            "Unset Breakpoint"
 7987        } else {
 7988            "Set Breakpoint"
 7989        };
 7990
 7991        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7992
 7993        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7994            BreakpointState::Enabled => Some("Disable"),
 7995            BreakpointState::Disabled => Some("Enable"),
 7996        });
 7997
 7998        let (anchor, breakpoint) =
 7999            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8000
 8001        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8002            menu.on_blur_subscription(Subscription::new(|| {}))
 8003                .context(focus_handle)
 8004                .when(run_to_cursor, |this| {
 8005                    let weak_editor = weak_editor.clone();
 8006                    this.entry("Run to cursor", None, move |window, cx| {
 8007                        weak_editor
 8008                            .update(cx, |editor, cx| {
 8009                                editor.change_selections(
 8010                                    SelectionEffects::no_scroll(),
 8011                                    window,
 8012                                    cx,
 8013                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8014                                );
 8015                            })
 8016                            .ok();
 8017
 8018                        window.dispatch_action(Box::new(RunToCursor), cx);
 8019                    })
 8020                    .separator()
 8021                })
 8022                .when_some(toggle_state_msg, |this, msg| {
 8023                    this.entry(msg, None, {
 8024                        let weak_editor = weak_editor.clone();
 8025                        let breakpoint = breakpoint.clone();
 8026                        move |_window, cx| {
 8027                            weak_editor
 8028                                .update(cx, |this, cx| {
 8029                                    this.edit_breakpoint_at_anchor(
 8030                                        anchor,
 8031                                        breakpoint.as_ref().clone(),
 8032                                        BreakpointEditAction::InvertState,
 8033                                        cx,
 8034                                    );
 8035                                })
 8036                                .log_err();
 8037                        }
 8038                    })
 8039                })
 8040                .entry(set_breakpoint_msg, None, {
 8041                    let weak_editor = weak_editor.clone();
 8042                    let breakpoint = breakpoint.clone();
 8043                    move |_window, cx| {
 8044                        weak_editor
 8045                            .update(cx, |this, cx| {
 8046                                this.edit_breakpoint_at_anchor(
 8047                                    anchor,
 8048                                    breakpoint.as_ref().clone(),
 8049                                    BreakpointEditAction::Toggle,
 8050                                    cx,
 8051                                );
 8052                            })
 8053                            .log_err();
 8054                    }
 8055                })
 8056                .entry(log_breakpoint_msg, None, {
 8057                    let breakpoint = breakpoint.clone();
 8058                    let weak_editor = weak_editor.clone();
 8059                    move |window, cx| {
 8060                        weak_editor
 8061                            .update(cx, |this, cx| {
 8062                                this.add_edit_breakpoint_block(
 8063                                    anchor,
 8064                                    breakpoint.as_ref(),
 8065                                    BreakpointPromptEditAction::Log,
 8066                                    window,
 8067                                    cx,
 8068                                );
 8069                            })
 8070                            .log_err();
 8071                    }
 8072                })
 8073                .entry(condition_breakpoint_msg, None, {
 8074                    let breakpoint = breakpoint.clone();
 8075                    let weak_editor = weak_editor.clone();
 8076                    move |window, cx| {
 8077                        weak_editor
 8078                            .update(cx, |this, cx| {
 8079                                this.add_edit_breakpoint_block(
 8080                                    anchor,
 8081                                    breakpoint.as_ref(),
 8082                                    BreakpointPromptEditAction::Condition,
 8083                                    window,
 8084                                    cx,
 8085                                );
 8086                            })
 8087                            .log_err();
 8088                    }
 8089                })
 8090                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8091                    weak_editor
 8092                        .update(cx, |this, cx| {
 8093                            this.add_edit_breakpoint_block(
 8094                                anchor,
 8095                                breakpoint.as_ref(),
 8096                                BreakpointPromptEditAction::HitCondition,
 8097                                window,
 8098                                cx,
 8099                            );
 8100                        })
 8101                        .log_err();
 8102                })
 8103        })
 8104    }
 8105
 8106    fn render_breakpoint(
 8107        &self,
 8108        position: Anchor,
 8109        row: DisplayRow,
 8110        breakpoint: &Breakpoint,
 8111        state: Option<BreakpointSessionState>,
 8112        cx: &mut Context<Self>,
 8113    ) -> IconButton {
 8114        let is_rejected = state.is_some_and(|s| !s.verified);
 8115        // Is it a breakpoint that shows up when hovering over gutter?
 8116        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8117            (false, false),
 8118            |PhantomBreakpointIndicator {
 8119                 is_active,
 8120                 display_row,
 8121                 collides_with_existing_breakpoint,
 8122             }| {
 8123                (
 8124                    is_active && display_row == row,
 8125                    collides_with_existing_breakpoint,
 8126                )
 8127            },
 8128        );
 8129
 8130        let (color, icon) = {
 8131            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8132                (false, false) => ui::IconName::DebugBreakpoint,
 8133                (true, false) => ui::IconName::DebugLogBreakpoint,
 8134                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8135                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8136            };
 8137
 8138            let color = if is_phantom {
 8139                Color::Hint
 8140            } else if is_rejected {
 8141                Color::Disabled
 8142            } else {
 8143                Color::Debugger
 8144            };
 8145
 8146            (color, icon)
 8147        };
 8148
 8149        let breakpoint = Arc::from(breakpoint.clone());
 8150
 8151        let alt_as_text = gpui::Keystroke {
 8152            modifiers: Modifiers::secondary_key(),
 8153            ..Default::default()
 8154        };
 8155        let primary_action_text = if breakpoint.is_disabled() {
 8156            "Enable breakpoint"
 8157        } else if is_phantom && !collides_with_existing {
 8158            "Set breakpoint"
 8159        } else {
 8160            "Unset breakpoint"
 8161        };
 8162        let focus_handle = self.focus_handle.clone();
 8163
 8164        let meta = if is_rejected {
 8165            SharedString::from("No executable code is associated with this line.")
 8166        } else if collides_with_existing && !breakpoint.is_disabled() {
 8167            SharedString::from(format!(
 8168                "{alt_as_text}-click to disable,\nright-click for more options."
 8169            ))
 8170        } else {
 8171            SharedString::from("Right-click for more options.")
 8172        };
 8173        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8174            .icon_size(IconSize::XSmall)
 8175            .size(ui::ButtonSize::None)
 8176            .when(is_rejected, |this| {
 8177                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8178            })
 8179            .icon_color(color)
 8180            .style(ButtonStyle::Transparent)
 8181            .on_click(cx.listener({
 8182                move |editor, event: &ClickEvent, window, cx| {
 8183                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8184                        BreakpointEditAction::InvertState
 8185                    } else {
 8186                        BreakpointEditAction::Toggle
 8187                    };
 8188
 8189                    window.focus(&editor.focus_handle(cx));
 8190                    editor.edit_breakpoint_at_anchor(
 8191                        position,
 8192                        breakpoint.as_ref().clone(),
 8193                        edit_action,
 8194                        cx,
 8195                    );
 8196                }
 8197            }))
 8198            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8199                editor.set_breakpoint_context_menu(
 8200                    row,
 8201                    Some(position),
 8202                    event.position(),
 8203                    window,
 8204                    cx,
 8205                );
 8206            }))
 8207            .tooltip(move |window, cx| {
 8208                Tooltip::with_meta_in(
 8209                    primary_action_text,
 8210                    Some(&ToggleBreakpoint),
 8211                    meta.clone(),
 8212                    &focus_handle,
 8213                    window,
 8214                    cx,
 8215                )
 8216            })
 8217    }
 8218
 8219    fn build_tasks_context(
 8220        project: &Entity<Project>,
 8221        buffer: &Entity<Buffer>,
 8222        buffer_row: u32,
 8223        tasks: &Arc<RunnableTasks>,
 8224        cx: &mut Context<Self>,
 8225    ) -> Task<Option<task::TaskContext>> {
 8226        let position = Point::new(buffer_row, tasks.column);
 8227        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8228        let location = Location {
 8229            buffer: buffer.clone(),
 8230            range: range_start..range_start,
 8231        };
 8232        // Fill in the environmental variables from the tree-sitter captures
 8233        let mut captured_task_variables = TaskVariables::default();
 8234        for (capture_name, value) in tasks.extra_variables.clone() {
 8235            captured_task_variables.insert(
 8236                task::VariableName::Custom(capture_name.into()),
 8237                value.clone(),
 8238            );
 8239        }
 8240        project.update(cx, |project, cx| {
 8241            project.task_store().update(cx, |task_store, cx| {
 8242                task_store.task_context_for_location(captured_task_variables, location, cx)
 8243            })
 8244        })
 8245    }
 8246
 8247    pub fn spawn_nearest_task(
 8248        &mut self,
 8249        action: &SpawnNearestTask,
 8250        window: &mut Window,
 8251        cx: &mut Context<Self>,
 8252    ) {
 8253        let Some((workspace, _)) = self.workspace.clone() else {
 8254            return;
 8255        };
 8256        let Some(project) = self.project.clone() else {
 8257            return;
 8258        };
 8259
 8260        // Try to find a closest, enclosing node using tree-sitter that has a task
 8261        let Some((buffer, buffer_row, tasks)) = self
 8262            .find_enclosing_node_task(cx)
 8263            // Or find the task that's closest in row-distance.
 8264            .or_else(|| self.find_closest_task(cx))
 8265        else {
 8266            return;
 8267        };
 8268
 8269        let reveal_strategy = action.reveal;
 8270        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8271        cx.spawn_in(window, async move |_, cx| {
 8272            let context = task_context.await?;
 8273            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8274
 8275            let resolved = &mut resolved_task.resolved;
 8276            resolved.reveal = reveal_strategy;
 8277
 8278            workspace
 8279                .update_in(cx, |workspace, window, cx| {
 8280                    workspace.schedule_resolved_task(
 8281                        task_source_kind,
 8282                        resolved_task,
 8283                        false,
 8284                        window,
 8285                        cx,
 8286                    );
 8287                })
 8288                .ok()
 8289        })
 8290        .detach();
 8291    }
 8292
 8293    fn find_closest_task(
 8294        &mut self,
 8295        cx: &mut Context<Self>,
 8296    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8297        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8298
 8299        let ((buffer_id, row), tasks) = self
 8300            .tasks
 8301            .iter()
 8302            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8303
 8304        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8305        let tasks = Arc::new(tasks.to_owned());
 8306        Some((buffer, *row, tasks))
 8307    }
 8308
 8309    fn find_enclosing_node_task(
 8310        &mut self,
 8311        cx: &mut Context<Self>,
 8312    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8313        let snapshot = self.buffer.read(cx).snapshot(cx);
 8314        let offset = self.selections.newest::<usize>(cx).head();
 8315        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8316        let buffer_id = excerpt.buffer().remote_id();
 8317
 8318        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8319        let mut cursor = layer.node().walk();
 8320
 8321        while cursor.goto_first_child_for_byte(offset).is_some() {
 8322            if cursor.node().end_byte() == offset {
 8323                cursor.goto_next_sibling();
 8324            }
 8325        }
 8326
 8327        // Ascend to the smallest ancestor that contains the range and has a task.
 8328        loop {
 8329            let node = cursor.node();
 8330            let node_range = node.byte_range();
 8331            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8332
 8333            // Check if this node contains our offset
 8334            if node_range.start <= offset && node_range.end >= offset {
 8335                // If it contains offset, check for task
 8336                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8337                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8338                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8339                }
 8340            }
 8341
 8342            if !cursor.goto_parent() {
 8343                break;
 8344            }
 8345        }
 8346        None
 8347    }
 8348
 8349    fn render_run_indicator(
 8350        &self,
 8351        _style: &EditorStyle,
 8352        is_active: bool,
 8353        row: DisplayRow,
 8354        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8355        cx: &mut Context<Self>,
 8356    ) -> IconButton {
 8357        let color = Color::Muted;
 8358        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8359
 8360        IconButton::new(
 8361            ("run_indicator", row.0 as usize),
 8362            ui::IconName::PlayOutlined,
 8363        )
 8364        .shape(ui::IconButtonShape::Square)
 8365        .icon_size(IconSize::XSmall)
 8366        .icon_color(color)
 8367        .toggle_state(is_active)
 8368        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8369            let quick_launch = match e {
 8370                ClickEvent::Keyboard(_) => true,
 8371                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8372            };
 8373
 8374            window.focus(&editor.focus_handle(cx));
 8375            editor.toggle_code_actions(
 8376                &ToggleCodeActions {
 8377                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8378                    quick_launch,
 8379                },
 8380                window,
 8381                cx,
 8382            );
 8383        }))
 8384        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8385            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8386        }))
 8387    }
 8388
 8389    pub fn context_menu_visible(&self) -> bool {
 8390        !self.edit_prediction_preview_is_active()
 8391            && self
 8392                .context_menu
 8393                .borrow()
 8394                .as_ref()
 8395                .is_some_and(|menu| menu.visible())
 8396    }
 8397
 8398    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8399        self.context_menu
 8400            .borrow()
 8401            .as_ref()
 8402            .map(|menu| menu.origin())
 8403    }
 8404
 8405    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8406        self.context_menu_options = Some(options);
 8407    }
 8408
 8409    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8410    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8411
 8412    fn render_edit_prediction_popover(
 8413        &mut self,
 8414        text_bounds: &Bounds<Pixels>,
 8415        content_origin: gpui::Point<Pixels>,
 8416        right_margin: Pixels,
 8417        editor_snapshot: &EditorSnapshot,
 8418        visible_row_range: Range<DisplayRow>,
 8419        scroll_top: f32,
 8420        scroll_bottom: f32,
 8421        line_layouts: &[LineWithInvisibles],
 8422        line_height: Pixels,
 8423        scroll_pixel_position: gpui::Point<Pixels>,
 8424        newest_selection_head: Option<DisplayPoint>,
 8425        editor_width: Pixels,
 8426        style: &EditorStyle,
 8427        window: &mut Window,
 8428        cx: &mut App,
 8429    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8430        if self.mode().is_minimap() {
 8431            return None;
 8432        }
 8433        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8434
 8435        if self.edit_prediction_visible_in_cursor_popover(true) {
 8436            return None;
 8437        }
 8438
 8439        match &active_edit_prediction.completion {
 8440            EditPrediction::Move { target, .. } => {
 8441                let target_display_point = target.to_display_point(editor_snapshot);
 8442
 8443                if self.edit_prediction_requires_modifier() {
 8444                    if !self.edit_prediction_preview_is_active() {
 8445                        return None;
 8446                    }
 8447
 8448                    self.render_edit_prediction_modifier_jump_popover(
 8449                        text_bounds,
 8450                        content_origin,
 8451                        visible_row_range,
 8452                        line_layouts,
 8453                        line_height,
 8454                        scroll_pixel_position,
 8455                        newest_selection_head,
 8456                        target_display_point,
 8457                        window,
 8458                        cx,
 8459                    )
 8460                } else {
 8461                    self.render_edit_prediction_eager_jump_popover(
 8462                        text_bounds,
 8463                        content_origin,
 8464                        editor_snapshot,
 8465                        visible_row_range,
 8466                        scroll_top,
 8467                        scroll_bottom,
 8468                        line_height,
 8469                        scroll_pixel_position,
 8470                        target_display_point,
 8471                        editor_width,
 8472                        window,
 8473                        cx,
 8474                    )
 8475                }
 8476            }
 8477            EditPrediction::Edit {
 8478                display_mode: EditDisplayMode::Inline,
 8479                ..
 8480            } => None,
 8481            EditPrediction::Edit {
 8482                display_mode: EditDisplayMode::TabAccept,
 8483                edits,
 8484                ..
 8485            } => {
 8486                let range = &edits.first()?.0;
 8487                let target_display_point = range.end.to_display_point(editor_snapshot);
 8488
 8489                self.render_edit_prediction_end_of_line_popover(
 8490                    "Accept",
 8491                    editor_snapshot,
 8492                    visible_row_range,
 8493                    target_display_point,
 8494                    line_height,
 8495                    scroll_pixel_position,
 8496                    content_origin,
 8497                    editor_width,
 8498                    window,
 8499                    cx,
 8500                )
 8501            }
 8502            EditPrediction::Edit {
 8503                edits,
 8504                edit_preview,
 8505                display_mode: EditDisplayMode::DiffPopover,
 8506                snapshot,
 8507            } => self.render_edit_prediction_diff_popover(
 8508                text_bounds,
 8509                content_origin,
 8510                right_margin,
 8511                editor_snapshot,
 8512                visible_row_range,
 8513                line_layouts,
 8514                line_height,
 8515                scroll_pixel_position,
 8516                newest_selection_head,
 8517                editor_width,
 8518                style,
 8519                edits,
 8520                edit_preview,
 8521                snapshot,
 8522                window,
 8523                cx,
 8524            ),
 8525        }
 8526    }
 8527
 8528    fn render_edit_prediction_modifier_jump_popover(
 8529        &mut self,
 8530        text_bounds: &Bounds<Pixels>,
 8531        content_origin: gpui::Point<Pixels>,
 8532        visible_row_range: Range<DisplayRow>,
 8533        line_layouts: &[LineWithInvisibles],
 8534        line_height: Pixels,
 8535        scroll_pixel_position: gpui::Point<Pixels>,
 8536        newest_selection_head: Option<DisplayPoint>,
 8537        target_display_point: DisplayPoint,
 8538        window: &mut Window,
 8539        cx: &mut App,
 8540    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8541        let scrolled_content_origin =
 8542            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8543
 8544        const SCROLL_PADDING_Y: Pixels = px(12.);
 8545
 8546        if target_display_point.row() < visible_row_range.start {
 8547            return self.render_edit_prediction_scroll_popover(
 8548                |_| SCROLL_PADDING_Y,
 8549                IconName::ArrowUp,
 8550                visible_row_range,
 8551                line_layouts,
 8552                newest_selection_head,
 8553                scrolled_content_origin,
 8554                window,
 8555                cx,
 8556            );
 8557        } else if target_display_point.row() >= visible_row_range.end {
 8558            return self.render_edit_prediction_scroll_popover(
 8559                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8560                IconName::ArrowDown,
 8561                visible_row_range,
 8562                line_layouts,
 8563                newest_selection_head,
 8564                scrolled_content_origin,
 8565                window,
 8566                cx,
 8567            );
 8568        }
 8569
 8570        const POLE_WIDTH: Pixels = px(2.);
 8571
 8572        let line_layout =
 8573            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8574        let target_column = target_display_point.column() as usize;
 8575
 8576        let target_x = line_layout.x_for_index(target_column);
 8577        let target_y =
 8578            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8579
 8580        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8581
 8582        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8583        border_color.l += 0.001;
 8584
 8585        let mut element = v_flex()
 8586            .items_end()
 8587            .when(flag_on_right, |el| el.items_start())
 8588            .child(if flag_on_right {
 8589                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8590                    .rounded_bl(px(0.))
 8591                    .rounded_tl(px(0.))
 8592                    .border_l_2()
 8593                    .border_color(border_color)
 8594            } else {
 8595                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8596                    .rounded_br(px(0.))
 8597                    .rounded_tr(px(0.))
 8598                    .border_r_2()
 8599                    .border_color(border_color)
 8600            })
 8601            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8602            .into_any();
 8603
 8604        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8605
 8606        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8607            - point(
 8608                if flag_on_right {
 8609                    POLE_WIDTH
 8610                } else {
 8611                    size.width - POLE_WIDTH
 8612                },
 8613                size.height - line_height,
 8614            );
 8615
 8616        origin.x = origin.x.max(content_origin.x);
 8617
 8618        element.prepaint_at(origin, window, cx);
 8619
 8620        Some((element, origin))
 8621    }
 8622
 8623    fn render_edit_prediction_scroll_popover(
 8624        &mut self,
 8625        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8626        scroll_icon: IconName,
 8627        visible_row_range: Range<DisplayRow>,
 8628        line_layouts: &[LineWithInvisibles],
 8629        newest_selection_head: Option<DisplayPoint>,
 8630        scrolled_content_origin: gpui::Point<Pixels>,
 8631        window: &mut Window,
 8632        cx: &mut App,
 8633    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8634        let mut element = self
 8635            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8636            .into_any();
 8637
 8638        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8639
 8640        let cursor = newest_selection_head?;
 8641        let cursor_row_layout =
 8642            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8643        let cursor_column = cursor.column() as usize;
 8644
 8645        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8646
 8647        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8648
 8649        element.prepaint_at(origin, window, cx);
 8650        Some((element, origin))
 8651    }
 8652
 8653    fn render_edit_prediction_eager_jump_popover(
 8654        &mut self,
 8655        text_bounds: &Bounds<Pixels>,
 8656        content_origin: gpui::Point<Pixels>,
 8657        editor_snapshot: &EditorSnapshot,
 8658        visible_row_range: Range<DisplayRow>,
 8659        scroll_top: f32,
 8660        scroll_bottom: f32,
 8661        line_height: Pixels,
 8662        scroll_pixel_position: gpui::Point<Pixels>,
 8663        target_display_point: DisplayPoint,
 8664        editor_width: Pixels,
 8665        window: &mut Window,
 8666        cx: &mut App,
 8667    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8668        if target_display_point.row().as_f32() < scroll_top {
 8669            let mut element = self
 8670                .render_edit_prediction_line_popover(
 8671                    "Jump to Edit",
 8672                    Some(IconName::ArrowUp),
 8673                    window,
 8674                    cx,
 8675                )?
 8676                .into_any();
 8677
 8678            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8679            let offset = point(
 8680                (text_bounds.size.width - size.width) / 2.,
 8681                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8682            );
 8683
 8684            let origin = text_bounds.origin + offset;
 8685            element.prepaint_at(origin, window, cx);
 8686            Some((element, origin))
 8687        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8688            let mut element = self
 8689                .render_edit_prediction_line_popover(
 8690                    "Jump to Edit",
 8691                    Some(IconName::ArrowDown),
 8692                    window,
 8693                    cx,
 8694                )?
 8695                .into_any();
 8696
 8697            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8698            let offset = point(
 8699                (text_bounds.size.width - size.width) / 2.,
 8700                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8701            );
 8702
 8703            let origin = text_bounds.origin + offset;
 8704            element.prepaint_at(origin, window, cx);
 8705            Some((element, origin))
 8706        } else {
 8707            self.render_edit_prediction_end_of_line_popover(
 8708                "Jump to Edit",
 8709                editor_snapshot,
 8710                visible_row_range,
 8711                target_display_point,
 8712                line_height,
 8713                scroll_pixel_position,
 8714                content_origin,
 8715                editor_width,
 8716                window,
 8717                cx,
 8718            )
 8719        }
 8720    }
 8721
 8722    fn render_edit_prediction_end_of_line_popover(
 8723        self: &mut Editor,
 8724        label: &'static str,
 8725        editor_snapshot: &EditorSnapshot,
 8726        visible_row_range: Range<DisplayRow>,
 8727        target_display_point: DisplayPoint,
 8728        line_height: Pixels,
 8729        scroll_pixel_position: gpui::Point<Pixels>,
 8730        content_origin: gpui::Point<Pixels>,
 8731        editor_width: Pixels,
 8732        window: &mut Window,
 8733        cx: &mut App,
 8734    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8735        let target_line_end = DisplayPoint::new(
 8736            target_display_point.row(),
 8737            editor_snapshot.line_len(target_display_point.row()),
 8738        );
 8739
 8740        let mut element = self
 8741            .render_edit_prediction_line_popover(label, None, window, cx)?
 8742            .into_any();
 8743
 8744        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8745
 8746        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8747
 8748        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8749        let mut origin = start_point
 8750            + line_origin
 8751            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8752        origin.x = origin.x.max(content_origin.x);
 8753
 8754        let max_x = content_origin.x + editor_width - size.width;
 8755
 8756        if origin.x > max_x {
 8757            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8758
 8759            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8760                origin.y += offset;
 8761                IconName::ArrowUp
 8762            } else {
 8763                origin.y -= offset;
 8764                IconName::ArrowDown
 8765            };
 8766
 8767            element = self
 8768                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8769                .into_any();
 8770
 8771            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8772
 8773            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8774        }
 8775
 8776        element.prepaint_at(origin, window, cx);
 8777        Some((element, origin))
 8778    }
 8779
 8780    fn render_edit_prediction_diff_popover(
 8781        self: &Editor,
 8782        text_bounds: &Bounds<Pixels>,
 8783        content_origin: gpui::Point<Pixels>,
 8784        right_margin: Pixels,
 8785        editor_snapshot: &EditorSnapshot,
 8786        visible_row_range: Range<DisplayRow>,
 8787        line_layouts: &[LineWithInvisibles],
 8788        line_height: Pixels,
 8789        scroll_pixel_position: gpui::Point<Pixels>,
 8790        newest_selection_head: Option<DisplayPoint>,
 8791        editor_width: Pixels,
 8792        style: &EditorStyle,
 8793        edits: &Vec<(Range<Anchor>, String)>,
 8794        edit_preview: &Option<language::EditPreview>,
 8795        snapshot: &language::BufferSnapshot,
 8796        window: &mut Window,
 8797        cx: &mut App,
 8798    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8799        let edit_start = edits
 8800            .first()
 8801            .unwrap()
 8802            .0
 8803            .start
 8804            .to_display_point(editor_snapshot);
 8805        let edit_end = edits
 8806            .last()
 8807            .unwrap()
 8808            .0
 8809            .end
 8810            .to_display_point(editor_snapshot);
 8811
 8812        let is_visible = visible_row_range.contains(&edit_start.row())
 8813            || visible_row_range.contains(&edit_end.row());
 8814        if !is_visible {
 8815            return None;
 8816        }
 8817
 8818        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8819            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8820        } else {
 8821            // Fallback for providers without edit_preview
 8822            crate::edit_prediction_fallback_text(edits, cx)
 8823        };
 8824
 8825        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8826        let line_count = highlighted_edits.text.lines().count();
 8827
 8828        const BORDER_WIDTH: Pixels = px(1.);
 8829
 8830        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8831        let has_keybind = keybind.is_some();
 8832
 8833        let mut element = h_flex()
 8834            .items_start()
 8835            .child(
 8836                h_flex()
 8837                    .bg(cx.theme().colors().editor_background)
 8838                    .border(BORDER_WIDTH)
 8839                    .shadow_xs()
 8840                    .border_color(cx.theme().colors().border)
 8841                    .rounded_l_lg()
 8842                    .when(line_count > 1, |el| el.rounded_br_lg())
 8843                    .pr_1()
 8844                    .child(styled_text),
 8845            )
 8846            .child(
 8847                h_flex()
 8848                    .h(line_height + BORDER_WIDTH * 2.)
 8849                    .px_1p5()
 8850                    .gap_1()
 8851                    // Workaround: For some reason, there's a gap if we don't do this
 8852                    .ml(-BORDER_WIDTH)
 8853                    .shadow(vec![gpui::BoxShadow {
 8854                        color: gpui::black().opacity(0.05),
 8855                        offset: point(px(1.), px(1.)),
 8856                        blur_radius: px(2.),
 8857                        spread_radius: px(0.),
 8858                    }])
 8859                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8860                    .border(BORDER_WIDTH)
 8861                    .border_color(cx.theme().colors().border)
 8862                    .rounded_r_lg()
 8863                    .id("edit_prediction_diff_popover_keybind")
 8864                    .when(!has_keybind, |el| {
 8865                        let status_colors = cx.theme().status();
 8866
 8867                        el.bg(status_colors.error_background)
 8868                            .border_color(status_colors.error.opacity(0.6))
 8869                            .child(Icon::new(IconName::Info).color(Color::Error))
 8870                            .cursor_default()
 8871                            .hoverable_tooltip(move |_window, cx| {
 8872                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8873                            })
 8874                    })
 8875                    .children(keybind),
 8876            )
 8877            .into_any();
 8878
 8879        let longest_row =
 8880            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8881        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8882            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8883        } else {
 8884            layout_line(
 8885                longest_row,
 8886                editor_snapshot,
 8887                style,
 8888                editor_width,
 8889                |_| false,
 8890                window,
 8891                cx,
 8892            )
 8893            .width
 8894        };
 8895
 8896        let viewport_bounds =
 8897            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8898                right: -right_margin,
 8899                ..Default::default()
 8900            });
 8901
 8902        let x_after_longest =
 8903            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8904                - scroll_pixel_position.x;
 8905
 8906        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8907
 8908        // Fully visible if it can be displayed within the window (allow overlapping other
 8909        // panes). However, this is only allowed if the popover starts within text_bounds.
 8910        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8911            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8912
 8913        let mut origin = if can_position_to_the_right {
 8914            point(
 8915                x_after_longest,
 8916                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8917                    - scroll_pixel_position.y,
 8918            )
 8919        } else {
 8920            let cursor_row = newest_selection_head.map(|head| head.row());
 8921            let above_edit = edit_start
 8922                .row()
 8923                .0
 8924                .checked_sub(line_count as u32)
 8925                .map(DisplayRow);
 8926            let below_edit = Some(edit_end.row() + 1);
 8927            let above_cursor =
 8928                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8929            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8930
 8931            // Place the edit popover adjacent to the edit if there is a location
 8932            // available that is onscreen and does not obscure the cursor. Otherwise,
 8933            // place it adjacent to the cursor.
 8934            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8935                .into_iter()
 8936                .flatten()
 8937                .find(|&start_row| {
 8938                    let end_row = start_row + line_count as u32;
 8939                    visible_row_range.contains(&start_row)
 8940                        && visible_row_range.contains(&end_row)
 8941                        && cursor_row
 8942                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8943                })?;
 8944
 8945            content_origin
 8946                + point(
 8947                    -scroll_pixel_position.x,
 8948                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8949                )
 8950        };
 8951
 8952        origin.x -= BORDER_WIDTH;
 8953
 8954        window.defer_draw(element, origin, 1);
 8955
 8956        // Do not return an element, since it will already be drawn due to defer_draw.
 8957        None
 8958    }
 8959
 8960    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8961        px(30.)
 8962    }
 8963
 8964    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8965        if self.read_only(cx) {
 8966            cx.theme().players().read_only()
 8967        } else {
 8968            self.style.as_ref().unwrap().local_player
 8969        }
 8970    }
 8971
 8972    fn render_edit_prediction_accept_keybind(
 8973        &self,
 8974        window: &mut Window,
 8975        cx: &App,
 8976    ) -> Option<AnyElement> {
 8977        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8978        let accept_keystroke = accept_binding.keystroke()?;
 8979
 8980        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8981
 8982        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8983            Color::Accent
 8984        } else {
 8985            Color::Muted
 8986        };
 8987
 8988        h_flex()
 8989            .px_0p5()
 8990            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8991            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8992            .text_size(TextSize::XSmall.rems(cx))
 8993            .child(h_flex().children(ui::render_modifiers(
 8994                &accept_keystroke.modifiers,
 8995                PlatformStyle::platform(),
 8996                Some(modifiers_color),
 8997                Some(IconSize::XSmall.rems().into()),
 8998                true,
 8999            )))
 9000            .when(is_platform_style_mac, |parent| {
 9001                parent.child(accept_keystroke.key.clone())
 9002            })
 9003            .when(!is_platform_style_mac, |parent| {
 9004                parent.child(
 9005                    Key::new(
 9006                        util::capitalize(&accept_keystroke.key),
 9007                        Some(Color::Default),
 9008                    )
 9009                    .size(Some(IconSize::XSmall.rems().into())),
 9010                )
 9011            })
 9012            .into_any()
 9013            .into()
 9014    }
 9015
 9016    fn render_edit_prediction_line_popover(
 9017        &self,
 9018        label: impl Into<SharedString>,
 9019        icon: Option<IconName>,
 9020        window: &mut Window,
 9021        cx: &App,
 9022    ) -> Option<Stateful<Div>> {
 9023        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9024
 9025        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9026        let has_keybind = keybind.is_some();
 9027
 9028        let result = h_flex()
 9029            .id("ep-line-popover")
 9030            .py_0p5()
 9031            .pl_1()
 9032            .pr(padding_right)
 9033            .gap_1()
 9034            .rounded_md()
 9035            .border_1()
 9036            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9037            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9038            .shadow_xs()
 9039            .when(!has_keybind, |el| {
 9040                let status_colors = cx.theme().status();
 9041
 9042                el.bg(status_colors.error_background)
 9043                    .border_color(status_colors.error.opacity(0.6))
 9044                    .pl_2()
 9045                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9046                    .cursor_default()
 9047                    .hoverable_tooltip(move |_window, cx| {
 9048                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9049                    })
 9050            })
 9051            .children(keybind)
 9052            .child(
 9053                Label::new(label)
 9054                    .size(LabelSize::Small)
 9055                    .when(!has_keybind, |el| {
 9056                        el.color(cx.theme().status().error.into()).strikethrough()
 9057                    }),
 9058            )
 9059            .when(!has_keybind, |el| {
 9060                el.child(
 9061                    h_flex().ml_1().child(
 9062                        Icon::new(IconName::Info)
 9063                            .size(IconSize::Small)
 9064                            .color(cx.theme().status().error.into()),
 9065                    ),
 9066                )
 9067            })
 9068            .when_some(icon, |element, icon| {
 9069                element.child(
 9070                    div()
 9071                        .mt(px(1.5))
 9072                        .child(Icon::new(icon).size(IconSize::Small)),
 9073                )
 9074            });
 9075
 9076        Some(result)
 9077    }
 9078
 9079    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9080        let accent_color = cx.theme().colors().text_accent;
 9081        let editor_bg_color = cx.theme().colors().editor_background;
 9082        editor_bg_color.blend(accent_color.opacity(0.1))
 9083    }
 9084
 9085    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9086        let accent_color = cx.theme().colors().text_accent;
 9087        let editor_bg_color = cx.theme().colors().editor_background;
 9088        editor_bg_color.blend(accent_color.opacity(0.6))
 9089    }
 9090    fn get_prediction_provider_icon_name(
 9091        provider: &Option<RegisteredEditPredictionProvider>,
 9092    ) -> IconName {
 9093        match provider {
 9094            Some(provider) => match provider.provider.name() {
 9095                "copilot" => IconName::Copilot,
 9096                "supermaven" => IconName::Supermaven,
 9097                _ => IconName::ZedPredict,
 9098            },
 9099            None => IconName::ZedPredict,
 9100        }
 9101    }
 9102
 9103    fn render_edit_prediction_cursor_popover(
 9104        &self,
 9105        min_width: Pixels,
 9106        max_width: Pixels,
 9107        cursor_point: Point,
 9108        style: &EditorStyle,
 9109        accept_keystroke: Option<&gpui::Keystroke>,
 9110        _window: &Window,
 9111        cx: &mut Context<Editor>,
 9112    ) -> Option<AnyElement> {
 9113        let provider = self.edit_prediction_provider.as_ref()?;
 9114        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9115
 9116        let is_refreshing = provider.provider.is_refreshing(cx);
 9117
 9118        fn pending_completion_container(icon: IconName) -> Div {
 9119            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9120        }
 9121
 9122        let completion = match &self.active_edit_prediction {
 9123            Some(prediction) => {
 9124                if !self.has_visible_completions_menu() {
 9125                    const RADIUS: Pixels = px(6.);
 9126                    const BORDER_WIDTH: Pixels = px(1.);
 9127
 9128                    return Some(
 9129                        h_flex()
 9130                            .elevation_2(cx)
 9131                            .border(BORDER_WIDTH)
 9132                            .border_color(cx.theme().colors().border)
 9133                            .when(accept_keystroke.is_none(), |el| {
 9134                                el.border_color(cx.theme().status().error)
 9135                            })
 9136                            .rounded(RADIUS)
 9137                            .rounded_tl(px(0.))
 9138                            .overflow_hidden()
 9139                            .child(div().px_1p5().child(match &prediction.completion {
 9140                                EditPrediction::Move { target, snapshot } => {
 9141                                    use text::ToPoint as _;
 9142                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9143                                    {
 9144                                        Icon::new(IconName::ZedPredictDown)
 9145                                    } else {
 9146                                        Icon::new(IconName::ZedPredictUp)
 9147                                    }
 9148                                }
 9149                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9150                            }))
 9151                            .child(
 9152                                h_flex()
 9153                                    .gap_1()
 9154                                    .py_1()
 9155                                    .px_2()
 9156                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9157                                    .border_l_1()
 9158                                    .border_color(cx.theme().colors().border)
 9159                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9160                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9161                                        el.child(
 9162                                            Label::new("Hold")
 9163                                                .size(LabelSize::Small)
 9164                                                .when(accept_keystroke.is_none(), |el| {
 9165                                                    el.strikethrough()
 9166                                                })
 9167                                                .line_height_style(LineHeightStyle::UiLabel),
 9168                                        )
 9169                                    })
 9170                                    .id("edit_prediction_cursor_popover_keybind")
 9171                                    .when(accept_keystroke.is_none(), |el| {
 9172                                        let status_colors = cx.theme().status();
 9173
 9174                                        el.bg(status_colors.error_background)
 9175                                            .border_color(status_colors.error.opacity(0.6))
 9176                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9177                                            .cursor_default()
 9178                                            .hoverable_tooltip(move |_window, cx| {
 9179                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9180                                                    .into()
 9181                                            })
 9182                                    })
 9183                                    .when_some(
 9184                                        accept_keystroke.as_ref(),
 9185                                        |el, accept_keystroke| {
 9186                                            el.child(h_flex().children(ui::render_modifiers(
 9187                                                &accept_keystroke.modifiers,
 9188                                                PlatformStyle::platform(),
 9189                                                Some(Color::Default),
 9190                                                Some(IconSize::XSmall.rems().into()),
 9191                                                false,
 9192                                            )))
 9193                                        },
 9194                                    ),
 9195                            )
 9196                            .into_any(),
 9197                    );
 9198                }
 9199
 9200                self.render_edit_prediction_cursor_popover_preview(
 9201                    prediction,
 9202                    cursor_point,
 9203                    style,
 9204                    cx,
 9205                )?
 9206            }
 9207
 9208            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9209                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9210                    stale_completion,
 9211                    cursor_point,
 9212                    style,
 9213                    cx,
 9214                )?,
 9215
 9216                None => pending_completion_container(provider_icon)
 9217                    .child(Label::new("...").size(LabelSize::Small)),
 9218            },
 9219
 9220            None => pending_completion_container(provider_icon)
 9221                .child(Label::new("...").size(LabelSize::Small)),
 9222        };
 9223
 9224        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9225            completion
 9226                .with_animation(
 9227                    "loading-completion",
 9228                    Animation::new(Duration::from_secs(2))
 9229                        .repeat()
 9230                        .with_easing(pulsating_between(0.4, 0.8)),
 9231                    |label, delta| label.opacity(delta),
 9232                )
 9233                .into_any_element()
 9234        } else {
 9235            completion.into_any_element()
 9236        };
 9237
 9238        let has_completion = self.active_edit_prediction.is_some();
 9239
 9240        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9241        Some(
 9242            h_flex()
 9243                .min_w(min_width)
 9244                .max_w(max_width)
 9245                .flex_1()
 9246                .elevation_2(cx)
 9247                .border_color(cx.theme().colors().border)
 9248                .child(
 9249                    div()
 9250                        .flex_1()
 9251                        .py_1()
 9252                        .px_2()
 9253                        .overflow_hidden()
 9254                        .child(completion),
 9255                )
 9256                .when_some(accept_keystroke, |el, accept_keystroke| {
 9257                    if !accept_keystroke.modifiers.modified() {
 9258                        return el;
 9259                    }
 9260
 9261                    el.child(
 9262                        h_flex()
 9263                            .h_full()
 9264                            .border_l_1()
 9265                            .rounded_r_lg()
 9266                            .border_color(cx.theme().colors().border)
 9267                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9268                            .gap_1()
 9269                            .py_1()
 9270                            .px_2()
 9271                            .child(
 9272                                h_flex()
 9273                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9274                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9275                                    .child(h_flex().children(ui::render_modifiers(
 9276                                        &accept_keystroke.modifiers,
 9277                                        PlatformStyle::platform(),
 9278                                        Some(if !has_completion {
 9279                                            Color::Muted
 9280                                        } else {
 9281                                            Color::Default
 9282                                        }),
 9283                                        None,
 9284                                        false,
 9285                                    ))),
 9286                            )
 9287                            .child(Label::new("Preview").into_any_element())
 9288                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9289                    )
 9290                })
 9291                .into_any(),
 9292        )
 9293    }
 9294
 9295    fn render_edit_prediction_cursor_popover_preview(
 9296        &self,
 9297        completion: &EditPredictionState,
 9298        cursor_point: Point,
 9299        style: &EditorStyle,
 9300        cx: &mut Context<Editor>,
 9301    ) -> Option<Div> {
 9302        use text::ToPoint as _;
 9303
 9304        fn render_relative_row_jump(
 9305            prefix: impl Into<String>,
 9306            current_row: u32,
 9307            target_row: u32,
 9308        ) -> Div {
 9309            let (row_diff, arrow) = if target_row < current_row {
 9310                (current_row - target_row, IconName::ArrowUp)
 9311            } else {
 9312                (target_row - current_row, IconName::ArrowDown)
 9313            };
 9314
 9315            h_flex()
 9316                .child(
 9317                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9318                        .color(Color::Muted)
 9319                        .size(LabelSize::Small),
 9320                )
 9321                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9322        }
 9323
 9324        let supports_jump = self
 9325            .edit_prediction_provider
 9326            .as_ref()
 9327            .map(|provider| provider.provider.supports_jump_to_edit())
 9328            .unwrap_or(true);
 9329
 9330        match &completion.completion {
 9331            EditPrediction::Move {
 9332                target, snapshot, ..
 9333            } => {
 9334                if !supports_jump {
 9335                    return None;
 9336                }
 9337
 9338                Some(
 9339                    h_flex()
 9340                        .px_2()
 9341                        .gap_2()
 9342                        .flex_1()
 9343                        .child(
 9344                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9345                                Icon::new(IconName::ZedPredictDown)
 9346                            } else {
 9347                                Icon::new(IconName::ZedPredictUp)
 9348                            },
 9349                        )
 9350                        .child(Label::new("Jump to Edit")),
 9351                )
 9352            }
 9353
 9354            EditPrediction::Edit {
 9355                edits,
 9356                edit_preview,
 9357                snapshot,
 9358                display_mode: _,
 9359            } => {
 9360                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9361
 9362                let (highlighted_edits, has_more_lines) =
 9363                    if let Some(edit_preview) = edit_preview.as_ref() {
 9364                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9365                            .first_line_preview()
 9366                    } else {
 9367                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9368                    };
 9369
 9370                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9371                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9372
 9373                let preview = h_flex()
 9374                    .gap_1()
 9375                    .min_w_16()
 9376                    .child(styled_text)
 9377                    .when(has_more_lines, |parent| parent.child(""));
 9378
 9379                let left = if supports_jump && first_edit_row != cursor_point.row {
 9380                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9381                        .into_any_element()
 9382                } else {
 9383                    let icon_name =
 9384                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9385                    Icon::new(icon_name).into_any_element()
 9386                };
 9387
 9388                Some(
 9389                    h_flex()
 9390                        .h_full()
 9391                        .flex_1()
 9392                        .gap_2()
 9393                        .pr_1()
 9394                        .overflow_x_hidden()
 9395                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9396                        .child(left)
 9397                        .child(preview),
 9398                )
 9399            }
 9400        }
 9401    }
 9402
 9403    pub fn render_context_menu(
 9404        &self,
 9405        style: &EditorStyle,
 9406        max_height_in_lines: u32,
 9407        window: &mut Window,
 9408        cx: &mut Context<Editor>,
 9409    ) -> Option<AnyElement> {
 9410        let menu = self.context_menu.borrow();
 9411        let menu = menu.as_ref()?;
 9412        if !menu.visible() {
 9413            return None;
 9414        };
 9415        Some(menu.render(style, max_height_in_lines, window, cx))
 9416    }
 9417
 9418    fn render_context_menu_aside(
 9419        &mut self,
 9420        max_size: Size<Pixels>,
 9421        window: &mut Window,
 9422        cx: &mut Context<Editor>,
 9423    ) -> Option<AnyElement> {
 9424        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9425            if menu.visible() {
 9426                menu.render_aside(max_size, window, cx)
 9427            } else {
 9428                None
 9429            }
 9430        })
 9431    }
 9432
 9433    fn hide_context_menu(
 9434        &mut self,
 9435        window: &mut Window,
 9436        cx: &mut Context<Self>,
 9437    ) -> Option<CodeContextMenu> {
 9438        cx.notify();
 9439        self.completion_tasks.clear();
 9440        let context_menu = self.context_menu.borrow_mut().take();
 9441        self.stale_edit_prediction_in_menu.take();
 9442        self.update_visible_edit_prediction(window, cx);
 9443        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9444            && let Some(completion_provider) = &self.completion_provider
 9445        {
 9446            completion_provider.selection_changed(None, window, cx);
 9447        }
 9448        context_menu
 9449    }
 9450
 9451    fn show_snippet_choices(
 9452        &mut self,
 9453        choices: &Vec<String>,
 9454        selection: Range<Anchor>,
 9455        cx: &mut Context<Self>,
 9456    ) {
 9457        let Some((_, buffer, _)) = self
 9458            .buffer()
 9459            .read(cx)
 9460            .excerpt_containing(selection.start, cx)
 9461        else {
 9462            return;
 9463        };
 9464        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9465        else {
 9466            return;
 9467        };
 9468        if buffer != end_buffer {
 9469            log::error!("expected anchor range to have matching buffer IDs");
 9470            return;
 9471        }
 9472
 9473        let id = post_inc(&mut self.next_completion_id);
 9474        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9475        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9476            CompletionsMenu::new_snippet_choices(
 9477                id,
 9478                true,
 9479                choices,
 9480                selection,
 9481                buffer,
 9482                snippet_sort_order,
 9483            ),
 9484        ));
 9485    }
 9486
 9487    pub fn insert_snippet(
 9488        &mut self,
 9489        insertion_ranges: &[Range<usize>],
 9490        snippet: Snippet,
 9491        window: &mut Window,
 9492        cx: &mut Context<Self>,
 9493    ) -> Result<()> {
 9494        struct Tabstop<T> {
 9495            is_end_tabstop: bool,
 9496            ranges: Vec<Range<T>>,
 9497            choices: Option<Vec<String>>,
 9498        }
 9499
 9500        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9501            let snippet_text: Arc<str> = snippet.text.clone().into();
 9502            let edits = insertion_ranges
 9503                .iter()
 9504                .cloned()
 9505                .map(|range| (range, snippet_text.clone()));
 9506            let autoindent_mode = AutoindentMode::Block {
 9507                original_indent_columns: Vec::new(),
 9508            };
 9509            buffer.edit(edits, Some(autoindent_mode), cx);
 9510
 9511            let snapshot = &*buffer.read(cx);
 9512            let snippet = &snippet;
 9513            snippet
 9514                .tabstops
 9515                .iter()
 9516                .map(|tabstop| {
 9517                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9518                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9519                    });
 9520                    let mut tabstop_ranges = tabstop
 9521                        .ranges
 9522                        .iter()
 9523                        .flat_map(|tabstop_range| {
 9524                            let mut delta = 0_isize;
 9525                            insertion_ranges.iter().map(move |insertion_range| {
 9526                                let insertion_start = insertion_range.start as isize + delta;
 9527                                delta +=
 9528                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9529
 9530                                let start = ((insertion_start + tabstop_range.start) as usize)
 9531                                    .min(snapshot.len());
 9532                                let end = ((insertion_start + tabstop_range.end) as usize)
 9533                                    .min(snapshot.len());
 9534                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9535                            })
 9536                        })
 9537                        .collect::<Vec<_>>();
 9538                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9539
 9540                    Tabstop {
 9541                        is_end_tabstop,
 9542                        ranges: tabstop_ranges,
 9543                        choices: tabstop.choices.clone(),
 9544                    }
 9545                })
 9546                .collect::<Vec<_>>()
 9547        });
 9548        if let Some(tabstop) = tabstops.first() {
 9549            self.change_selections(Default::default(), window, cx, |s| {
 9550                // Reverse order so that the first range is the newest created selection.
 9551                // Completions will use it and autoscroll will prioritize it.
 9552                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9553            });
 9554
 9555            if let Some(choices) = &tabstop.choices
 9556                && let Some(selection) = tabstop.ranges.first()
 9557            {
 9558                self.show_snippet_choices(choices, selection.clone(), cx)
 9559            }
 9560
 9561            // If we're already at the last tabstop and it's at the end of the snippet,
 9562            // we're done, we don't need to keep the state around.
 9563            if !tabstop.is_end_tabstop {
 9564                let choices = tabstops
 9565                    .iter()
 9566                    .map(|tabstop| tabstop.choices.clone())
 9567                    .collect();
 9568
 9569                let ranges = tabstops
 9570                    .into_iter()
 9571                    .map(|tabstop| tabstop.ranges)
 9572                    .collect::<Vec<_>>();
 9573
 9574                self.snippet_stack.push(SnippetState {
 9575                    active_index: 0,
 9576                    ranges,
 9577                    choices,
 9578                });
 9579            }
 9580
 9581            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9582            if self.autoclose_regions.is_empty() {
 9583                let snapshot = self.buffer.read(cx).snapshot(cx);
 9584                let mut all_selections = self.selections.all::<Point>(cx);
 9585                for selection in &mut all_selections {
 9586                    let selection_head = selection.head();
 9587                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9588                        continue;
 9589                    };
 9590
 9591                    let mut bracket_pair = None;
 9592                    let max_lookup_length = scope
 9593                        .brackets()
 9594                        .map(|(pair, _)| {
 9595                            pair.start
 9596                                .as_str()
 9597                                .chars()
 9598                                .count()
 9599                                .max(pair.end.as_str().chars().count())
 9600                        })
 9601                        .max();
 9602                    if let Some(max_lookup_length) = max_lookup_length {
 9603                        let next_text = snapshot
 9604                            .chars_at(selection_head)
 9605                            .take(max_lookup_length)
 9606                            .collect::<String>();
 9607                        let prev_text = snapshot
 9608                            .reversed_chars_at(selection_head)
 9609                            .take(max_lookup_length)
 9610                            .collect::<String>();
 9611
 9612                        for (pair, enabled) in scope.brackets() {
 9613                            if enabled
 9614                                && pair.close
 9615                                && prev_text.starts_with(pair.start.as_str())
 9616                                && next_text.starts_with(pair.end.as_str())
 9617                            {
 9618                                bracket_pair = Some(pair.clone());
 9619                                break;
 9620                            }
 9621                        }
 9622                    }
 9623
 9624                    if let Some(pair) = bracket_pair {
 9625                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9626                        let autoclose_enabled =
 9627                            self.use_autoclose && snapshot_settings.use_autoclose;
 9628                        if autoclose_enabled {
 9629                            let start = snapshot.anchor_after(selection_head);
 9630                            let end = snapshot.anchor_after(selection_head);
 9631                            self.autoclose_regions.push(AutocloseRegion {
 9632                                selection_id: selection.id,
 9633                                range: start..end,
 9634                                pair,
 9635                            });
 9636                        }
 9637                    }
 9638                }
 9639            }
 9640        }
 9641        Ok(())
 9642    }
 9643
 9644    pub fn move_to_next_snippet_tabstop(
 9645        &mut self,
 9646        window: &mut Window,
 9647        cx: &mut Context<Self>,
 9648    ) -> bool {
 9649        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9650    }
 9651
 9652    pub fn move_to_prev_snippet_tabstop(
 9653        &mut self,
 9654        window: &mut Window,
 9655        cx: &mut Context<Self>,
 9656    ) -> bool {
 9657        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9658    }
 9659
 9660    pub fn move_to_snippet_tabstop(
 9661        &mut self,
 9662        bias: Bias,
 9663        window: &mut Window,
 9664        cx: &mut Context<Self>,
 9665    ) -> bool {
 9666        if let Some(mut snippet) = self.snippet_stack.pop() {
 9667            match bias {
 9668                Bias::Left => {
 9669                    if snippet.active_index > 0 {
 9670                        snippet.active_index -= 1;
 9671                    } else {
 9672                        self.snippet_stack.push(snippet);
 9673                        return false;
 9674                    }
 9675                }
 9676                Bias::Right => {
 9677                    if snippet.active_index + 1 < snippet.ranges.len() {
 9678                        snippet.active_index += 1;
 9679                    } else {
 9680                        self.snippet_stack.push(snippet);
 9681                        return false;
 9682                    }
 9683                }
 9684            }
 9685            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9686                self.change_selections(Default::default(), window, cx, |s| {
 9687                    // Reverse order so that the first range is the newest created selection.
 9688                    // Completions will use it and autoscroll will prioritize it.
 9689                    s.select_ranges(current_ranges.iter().rev().cloned())
 9690                });
 9691
 9692                if let Some(choices) = &snippet.choices[snippet.active_index]
 9693                    && let Some(selection) = current_ranges.first()
 9694                {
 9695                    self.show_snippet_choices(choices, selection.clone(), cx);
 9696                }
 9697
 9698                // If snippet state is not at the last tabstop, push it back on the stack
 9699                if snippet.active_index + 1 < snippet.ranges.len() {
 9700                    self.snippet_stack.push(snippet);
 9701                }
 9702                return true;
 9703            }
 9704        }
 9705
 9706        false
 9707    }
 9708
 9709    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9710        self.transact(window, cx, |this, window, cx| {
 9711            this.select_all(&SelectAll, window, cx);
 9712            this.insert("", window, cx);
 9713        });
 9714    }
 9715
 9716    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9717        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9718        self.transact(window, cx, |this, window, cx| {
 9719            this.select_autoclose_pair(window, cx);
 9720            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9721            if !this.linked_edit_ranges.is_empty() {
 9722                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9723                let snapshot = this.buffer.read(cx).snapshot(cx);
 9724
 9725                for selection in selections.iter() {
 9726                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9727                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9728                    if selection_start.buffer_id != selection_end.buffer_id {
 9729                        continue;
 9730                    }
 9731                    if let Some(ranges) =
 9732                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9733                    {
 9734                        for (buffer, entries) in ranges {
 9735                            linked_ranges.entry(buffer).or_default().extend(entries);
 9736                        }
 9737                    }
 9738                }
 9739            }
 9740
 9741            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9742            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9743            for selection in &mut selections {
 9744                if selection.is_empty() {
 9745                    let old_head = selection.head();
 9746                    let mut new_head =
 9747                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9748                            .to_point(&display_map);
 9749                    if let Some((buffer, line_buffer_range)) = display_map
 9750                        .buffer_snapshot
 9751                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9752                    {
 9753                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9754                        let indent_len = match indent_size.kind {
 9755                            IndentKind::Space => {
 9756                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9757                            }
 9758                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9759                        };
 9760                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9761                            let indent_len = indent_len.get();
 9762                            new_head = cmp::min(
 9763                                new_head,
 9764                                MultiBufferPoint::new(
 9765                                    old_head.row,
 9766                                    ((old_head.column - 1) / indent_len) * indent_len,
 9767                                ),
 9768                            );
 9769                        }
 9770                    }
 9771
 9772                    selection.set_head(new_head, SelectionGoal::None);
 9773                }
 9774            }
 9775
 9776            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9777            this.insert("", window, cx);
 9778            let empty_str: Arc<str> = Arc::from("");
 9779            for (buffer, edits) in linked_ranges {
 9780                let snapshot = buffer.read(cx).snapshot();
 9781                use text::ToPoint as TP;
 9782
 9783                let edits = edits
 9784                    .into_iter()
 9785                    .map(|range| {
 9786                        let end_point = TP::to_point(&range.end, &snapshot);
 9787                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9788
 9789                        if end_point == start_point {
 9790                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9791                                .saturating_sub(1);
 9792                            start_point =
 9793                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9794                        };
 9795
 9796                        (start_point..end_point, empty_str.clone())
 9797                    })
 9798                    .sorted_by_key(|(range, _)| range.start)
 9799                    .collect::<Vec<_>>();
 9800                buffer.update(cx, |this, cx| {
 9801                    this.edit(edits, None, cx);
 9802                })
 9803            }
 9804            this.refresh_edit_prediction(true, false, window, cx);
 9805            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9806        });
 9807    }
 9808
 9809    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9810        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9811        self.transact(window, cx, |this, window, cx| {
 9812            this.change_selections(Default::default(), window, cx, |s| {
 9813                s.move_with(|map, selection| {
 9814                    if selection.is_empty() {
 9815                        let cursor = movement::right(map, selection.head());
 9816                        selection.end = cursor;
 9817                        selection.reversed = true;
 9818                        selection.goal = SelectionGoal::None;
 9819                    }
 9820                })
 9821            });
 9822            this.insert("", window, cx);
 9823            this.refresh_edit_prediction(true, false, window, cx);
 9824        });
 9825    }
 9826
 9827    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9828        if self.mode.is_single_line() {
 9829            cx.propagate();
 9830            return;
 9831        }
 9832
 9833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9834        if self.move_to_prev_snippet_tabstop(window, cx) {
 9835            return;
 9836        }
 9837        self.outdent(&Outdent, window, cx);
 9838    }
 9839
 9840    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9841        if self.mode.is_single_line() {
 9842            cx.propagate();
 9843            return;
 9844        }
 9845
 9846        if self.move_to_next_snippet_tabstop(window, cx) {
 9847            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848            return;
 9849        }
 9850        if self.read_only(cx) {
 9851            return;
 9852        }
 9853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9854        let mut selections = self.selections.all_adjusted(cx);
 9855        let buffer = self.buffer.read(cx);
 9856        let snapshot = buffer.snapshot(cx);
 9857        let rows_iter = selections.iter().map(|s| s.head().row);
 9858        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9859
 9860        let has_some_cursor_in_whitespace = selections
 9861            .iter()
 9862            .filter(|selection| selection.is_empty())
 9863            .any(|selection| {
 9864                let cursor = selection.head();
 9865                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9866                cursor.column < current_indent.len
 9867            });
 9868
 9869        let mut edits = Vec::new();
 9870        let mut prev_edited_row = 0;
 9871        let mut row_delta = 0;
 9872        for selection in &mut selections {
 9873            if selection.start.row != prev_edited_row {
 9874                row_delta = 0;
 9875            }
 9876            prev_edited_row = selection.end.row;
 9877
 9878            // If the selection is non-empty, then increase the indentation of the selected lines.
 9879            if !selection.is_empty() {
 9880                row_delta =
 9881                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9882                continue;
 9883            }
 9884
 9885            let cursor = selection.head();
 9886            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9887            if let Some(suggested_indent) =
 9888                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9889            {
 9890                // Don't do anything if already at suggested indent
 9891                // and there is any other cursor which is not
 9892                if has_some_cursor_in_whitespace
 9893                    && cursor.column == current_indent.len
 9894                    && current_indent.len == suggested_indent.len
 9895                {
 9896                    continue;
 9897                }
 9898
 9899                // Adjust line and move cursor to suggested indent
 9900                // if cursor is not at suggested indent
 9901                if cursor.column < suggested_indent.len
 9902                    && cursor.column <= current_indent.len
 9903                    && current_indent.len <= suggested_indent.len
 9904                {
 9905                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9906                    selection.end = selection.start;
 9907                    if row_delta == 0 {
 9908                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9909                            cursor.row,
 9910                            current_indent,
 9911                            suggested_indent,
 9912                        ));
 9913                        row_delta = suggested_indent.len - current_indent.len;
 9914                    }
 9915                    continue;
 9916                }
 9917
 9918                // If current indent is more than suggested indent
 9919                // only move cursor to current indent and skip indent
 9920                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9921                    selection.start = Point::new(cursor.row, current_indent.len);
 9922                    selection.end = selection.start;
 9923                    continue;
 9924                }
 9925            }
 9926
 9927            // Otherwise, insert a hard or soft tab.
 9928            let settings = buffer.language_settings_at(cursor, cx);
 9929            let tab_size = if settings.hard_tabs {
 9930                IndentSize::tab()
 9931            } else {
 9932                let tab_size = settings.tab_size.get();
 9933                let indent_remainder = snapshot
 9934                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9935                    .flat_map(str::chars)
 9936                    .fold(row_delta % tab_size, |counter: u32, c| {
 9937                        if c == '\t' {
 9938                            0
 9939                        } else {
 9940                            (counter + 1) % tab_size
 9941                        }
 9942                    });
 9943
 9944                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9945                IndentSize::spaces(chars_to_next_tab_stop)
 9946            };
 9947            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9948            selection.end = selection.start;
 9949            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9950            row_delta += tab_size.len;
 9951        }
 9952
 9953        self.transact(window, cx, |this, window, cx| {
 9954            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9955            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9956            this.refresh_edit_prediction(true, false, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.read_only(cx) {
 9962            return;
 9963        }
 9964        if self.mode.is_single_line() {
 9965            cx.propagate();
 9966            return;
 9967        }
 9968
 9969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9970        let mut selections = self.selections.all::<Point>(cx);
 9971        let mut prev_edited_row = 0;
 9972        let mut row_delta = 0;
 9973        let mut edits = Vec::new();
 9974        let buffer = self.buffer.read(cx);
 9975        let snapshot = buffer.snapshot(cx);
 9976        for selection in &mut selections {
 9977            if selection.start.row != prev_edited_row {
 9978                row_delta = 0;
 9979            }
 9980            prev_edited_row = selection.end.row;
 9981
 9982            row_delta =
 9983                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9984        }
 9985
 9986        self.transact(window, cx, |this, window, cx| {
 9987            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9988            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9989        });
 9990    }
 9991
 9992    fn indent_selection(
 9993        buffer: &MultiBuffer,
 9994        snapshot: &MultiBufferSnapshot,
 9995        selection: &mut Selection<Point>,
 9996        edits: &mut Vec<(Range<Point>, String)>,
 9997        delta_for_start_row: u32,
 9998        cx: &App,
 9999    ) -> u32 {
10000        let settings = buffer.language_settings_at(selection.start, cx);
10001        let tab_size = settings.tab_size.get();
10002        let indent_kind = if settings.hard_tabs {
10003            IndentKind::Tab
10004        } else {
10005            IndentKind::Space
10006        };
10007        let mut start_row = selection.start.row;
10008        let mut end_row = selection.end.row + 1;
10009
10010        // If a selection ends at the beginning of a line, don't indent
10011        // that last line.
10012        if selection.end.column == 0 && selection.end.row > selection.start.row {
10013            end_row -= 1;
10014        }
10015
10016        // Avoid re-indenting a row that has already been indented by a
10017        // previous selection, but still update this selection's column
10018        // to reflect that indentation.
10019        if delta_for_start_row > 0 {
10020            start_row += 1;
10021            selection.start.column += delta_for_start_row;
10022            if selection.end.row == selection.start.row {
10023                selection.end.column += delta_for_start_row;
10024            }
10025        }
10026
10027        let mut delta_for_end_row = 0;
10028        let has_multiple_rows = start_row + 1 != end_row;
10029        for row in start_row..end_row {
10030            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10031            let indent_delta = match (current_indent.kind, indent_kind) {
10032                (IndentKind::Space, IndentKind::Space) => {
10033                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10034                    IndentSize::spaces(columns_to_next_tab_stop)
10035                }
10036                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10037                (_, IndentKind::Tab) => IndentSize::tab(),
10038            };
10039
10040            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10041                0
10042            } else {
10043                selection.start.column
10044            };
10045            let row_start = Point::new(row, start);
10046            edits.push((
10047                row_start..row_start,
10048                indent_delta.chars().collect::<String>(),
10049            ));
10050
10051            // Update this selection's endpoints to reflect the indentation.
10052            if row == selection.start.row {
10053                selection.start.column += indent_delta.len;
10054            }
10055            if row == selection.end.row {
10056                selection.end.column += indent_delta.len;
10057                delta_for_end_row = indent_delta.len;
10058            }
10059        }
10060
10061        if selection.start.row == selection.end.row {
10062            delta_for_start_row + delta_for_end_row
10063        } else {
10064            delta_for_end_row
10065        }
10066    }
10067
10068    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10069        if self.read_only(cx) {
10070            return;
10071        }
10072        if self.mode.is_single_line() {
10073            cx.propagate();
10074            return;
10075        }
10076
10077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10079        let selections = self.selections.all::<Point>(cx);
10080        let mut deletion_ranges = Vec::new();
10081        let mut last_outdent = None;
10082        {
10083            let buffer = self.buffer.read(cx);
10084            let snapshot = buffer.snapshot(cx);
10085            for selection in &selections {
10086                let settings = buffer.language_settings_at(selection.start, cx);
10087                let tab_size = settings.tab_size.get();
10088                let mut rows = selection.spanned_rows(false, &display_map);
10089
10090                // Avoid re-outdenting a row that has already been outdented by a
10091                // previous selection.
10092                if let Some(last_row) = last_outdent
10093                    && last_row == rows.start
10094                {
10095                    rows.start = rows.start.next_row();
10096                }
10097                let has_multiple_rows = rows.len() > 1;
10098                for row in rows.iter_rows() {
10099                    let indent_size = snapshot.indent_size_for_line(row);
10100                    if indent_size.len > 0 {
10101                        let deletion_len = match indent_size.kind {
10102                            IndentKind::Space => {
10103                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10104                                if columns_to_prev_tab_stop == 0 {
10105                                    tab_size
10106                                } else {
10107                                    columns_to_prev_tab_stop
10108                                }
10109                            }
10110                            IndentKind::Tab => 1,
10111                        };
10112                        let start = if has_multiple_rows
10113                            || deletion_len > selection.start.column
10114                            || indent_size.len < selection.start.column
10115                        {
10116                            0
10117                        } else {
10118                            selection.start.column - deletion_len
10119                        };
10120                        deletion_ranges.push(
10121                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10122                        );
10123                        last_outdent = Some(row);
10124                    }
10125                }
10126            }
10127        }
10128
10129        self.transact(window, cx, |this, window, cx| {
10130            this.buffer.update(cx, |buffer, cx| {
10131                let empty_str: Arc<str> = Arc::default();
10132                buffer.edit(
10133                    deletion_ranges
10134                        .into_iter()
10135                        .map(|range| (range, empty_str.clone())),
10136                    None,
10137                    cx,
10138                );
10139            });
10140            let selections = this.selections.all::<usize>(cx);
10141            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10142        });
10143    }
10144
10145    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10146        if self.read_only(cx) {
10147            return;
10148        }
10149        if self.mode.is_single_line() {
10150            cx.propagate();
10151            return;
10152        }
10153
10154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10155        let selections = self
10156            .selections
10157            .all::<usize>(cx)
10158            .into_iter()
10159            .map(|s| s.range());
10160
10161        self.transact(window, cx, |this, window, cx| {
10162            this.buffer.update(cx, |buffer, cx| {
10163                buffer.autoindent_ranges(selections, cx);
10164            });
10165            let selections = this.selections.all::<usize>(cx);
10166            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10167        });
10168    }
10169
10170    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10173        let selections = self.selections.all::<Point>(cx);
10174
10175        let mut new_cursors = Vec::new();
10176        let mut edit_ranges = Vec::new();
10177        let mut selections = selections.iter().peekable();
10178        while let Some(selection) = selections.next() {
10179            let mut rows = selection.spanned_rows(false, &display_map);
10180            let goal_display_column = selection.head().to_display_point(&display_map).column();
10181
10182            // Accumulate contiguous regions of rows that we want to delete.
10183            while let Some(next_selection) = selections.peek() {
10184                let next_rows = next_selection.spanned_rows(false, &display_map);
10185                if next_rows.start <= rows.end {
10186                    rows.end = next_rows.end;
10187                    selections.next().unwrap();
10188                } else {
10189                    break;
10190                }
10191            }
10192
10193            let buffer = &display_map.buffer_snapshot;
10194            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10195            let edit_end;
10196            let cursor_buffer_row;
10197            if buffer.max_point().row >= rows.end.0 {
10198                // If there's a line after the range, delete the \n from the end of the row range
10199                // and position the cursor on the next line.
10200                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10201                cursor_buffer_row = rows.end;
10202            } else {
10203                // If there isn't a line after the range, delete the \n from the line before the
10204                // start of the row range and position the cursor there.
10205                edit_start = edit_start.saturating_sub(1);
10206                edit_end = buffer.len();
10207                cursor_buffer_row = rows.start.previous_row();
10208            }
10209
10210            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10211            *cursor.column_mut() =
10212                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10213
10214            new_cursors.push((
10215                selection.id,
10216                buffer.anchor_after(cursor.to_point(&display_map)),
10217            ));
10218            edit_ranges.push(edit_start..edit_end);
10219        }
10220
10221        self.transact(window, cx, |this, window, cx| {
10222            let buffer = this.buffer.update(cx, |buffer, cx| {
10223                let empty_str: Arc<str> = Arc::default();
10224                buffer.edit(
10225                    edit_ranges
10226                        .into_iter()
10227                        .map(|range| (range, empty_str.clone())),
10228                    None,
10229                    cx,
10230                );
10231                buffer.snapshot(cx)
10232            });
10233            let new_selections = new_cursors
10234                .into_iter()
10235                .map(|(id, cursor)| {
10236                    let cursor = cursor.to_point(&buffer);
10237                    Selection {
10238                        id,
10239                        start: cursor,
10240                        end: cursor,
10241                        reversed: false,
10242                        goal: SelectionGoal::None,
10243                    }
10244                })
10245                .collect();
10246
10247            this.change_selections(Default::default(), window, cx, |s| {
10248                s.select(new_selections);
10249            });
10250        });
10251    }
10252
10253    pub fn join_lines_impl(
10254        &mut self,
10255        insert_whitespace: bool,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10263        for selection in self.selections.all::<Point>(cx) {
10264            let start = MultiBufferRow(selection.start.row);
10265            // Treat single line selections as if they include the next line. Otherwise this action
10266            // would do nothing for single line selections individual cursors.
10267            let end = if selection.start.row == selection.end.row {
10268                MultiBufferRow(selection.start.row + 1)
10269            } else {
10270                MultiBufferRow(selection.end.row)
10271            };
10272
10273            if let Some(last_row_range) = row_ranges.last_mut()
10274                && start <= last_row_range.end
10275            {
10276                last_row_range.end = end;
10277                continue;
10278            }
10279            row_ranges.push(start..end);
10280        }
10281
10282        let snapshot = self.buffer.read(cx).snapshot(cx);
10283        let mut cursor_positions = Vec::new();
10284        for row_range in &row_ranges {
10285            let anchor = snapshot.anchor_before(Point::new(
10286                row_range.end.previous_row().0,
10287                snapshot.line_len(row_range.end.previous_row()),
10288            ));
10289            cursor_positions.push(anchor..anchor);
10290        }
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            for row_range in row_ranges.into_iter().rev() {
10294                for row in row_range.iter_rows().rev() {
10295                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10296                    let next_line_row = row.next_row();
10297                    let indent = snapshot.indent_size_for_line(next_line_row);
10298                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10299
10300                    let replace =
10301                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10302                            " "
10303                        } else {
10304                            ""
10305                        };
10306
10307                    this.buffer.update(cx, |buffer, cx| {
10308                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10309                    });
10310                }
10311            }
10312
10313            this.change_selections(Default::default(), window, cx, |s| {
10314                s.select_anchor_ranges(cursor_positions)
10315            });
10316        });
10317    }
10318
10319    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10321        self.join_lines_impl(true, window, cx);
10322    }
10323
10324    pub fn sort_lines_case_sensitive(
10325        &mut self,
10326        _: &SortLinesCaseSensitive,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10331    }
10332
10333    pub fn sort_lines_by_length(
10334        &mut self,
10335        _: &SortLinesByLength,
10336        window: &mut Window,
10337        cx: &mut Context<Self>,
10338    ) {
10339        self.manipulate_immutable_lines(window, cx, |lines| {
10340            lines.sort_by_key(|&line| line.chars().count())
10341        })
10342    }
10343
10344    pub fn sort_lines_case_insensitive(
10345        &mut self,
10346        _: &SortLinesCaseInsensitive,
10347        window: &mut Window,
10348        cx: &mut Context<Self>,
10349    ) {
10350        self.manipulate_immutable_lines(window, cx, |lines| {
10351            lines.sort_by_key(|line| line.to_lowercase())
10352        })
10353    }
10354
10355    pub fn unique_lines_case_insensitive(
10356        &mut self,
10357        _: &UniqueLinesCaseInsensitive,
10358        window: &mut Window,
10359        cx: &mut Context<Self>,
10360    ) {
10361        self.manipulate_immutable_lines(window, cx, |lines| {
10362            let mut seen = HashSet::default();
10363            lines.retain(|line| seen.insert(line.to_lowercase()));
10364        })
10365    }
10366
10367    pub fn unique_lines_case_sensitive(
10368        &mut self,
10369        _: &UniqueLinesCaseSensitive,
10370        window: &mut Window,
10371        cx: &mut Context<Self>,
10372    ) {
10373        self.manipulate_immutable_lines(window, cx, |lines| {
10374            let mut seen = HashSet::default();
10375            lines.retain(|line| seen.insert(*line));
10376        })
10377    }
10378
10379    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10380        let Some(project) = self.project.clone() else {
10381            return;
10382        };
10383        self.reload(project, window, cx)
10384            .detach_and_notify_err(window, cx);
10385    }
10386
10387    pub fn restore_file(
10388        &mut self,
10389        _: &::git::RestoreFile,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10394        let mut buffer_ids = HashSet::default();
10395        let snapshot = self.buffer().read(cx).snapshot(cx);
10396        for selection in self.selections.all::<usize>(cx) {
10397            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10398        }
10399
10400        let buffer = self.buffer().read(cx);
10401        let ranges = buffer_ids
10402            .into_iter()
10403            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10404            .collect::<Vec<_>>();
10405
10406        self.restore_hunks_in_ranges(ranges, window, cx);
10407    }
10408
10409    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10411        let selections = self
10412            .selections
10413            .all(cx)
10414            .into_iter()
10415            .map(|s| s.range())
10416            .collect();
10417        self.restore_hunks_in_ranges(selections, window, cx);
10418    }
10419
10420    pub fn restore_hunks_in_ranges(
10421        &mut self,
10422        ranges: Vec<Range<Point>>,
10423        window: &mut Window,
10424        cx: &mut Context<Editor>,
10425    ) {
10426        let mut revert_changes = HashMap::default();
10427        let chunk_by = self
10428            .snapshot(window, cx)
10429            .hunks_for_ranges(ranges)
10430            .into_iter()
10431            .chunk_by(|hunk| hunk.buffer_id);
10432        for (buffer_id, hunks) in &chunk_by {
10433            let hunks = hunks.collect::<Vec<_>>();
10434            for hunk in &hunks {
10435                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10436            }
10437            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10438        }
10439        drop(chunk_by);
10440        if !revert_changes.is_empty() {
10441            self.transact(window, cx, |editor, window, cx| {
10442                editor.restore(revert_changes, window, cx);
10443            });
10444        }
10445    }
10446
10447    pub fn open_active_item_in_terminal(
10448        &mut self,
10449        _: &OpenInTerminal,
10450        window: &mut Window,
10451        cx: &mut Context<Self>,
10452    ) {
10453        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10454            let project_path = buffer.read(cx).project_path(cx)?;
10455            let project = self.project()?.read(cx);
10456            let entry = project.entry_for_path(&project_path, cx)?;
10457            let parent = match &entry.canonical_path {
10458                Some(canonical_path) => canonical_path.to_path_buf(),
10459                None => project.absolute_path(&project_path, cx)?,
10460            }
10461            .parent()?
10462            .to_path_buf();
10463            Some(parent)
10464        }) {
10465            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10466        }
10467    }
10468
10469    fn set_breakpoint_context_menu(
10470        &mut self,
10471        display_row: DisplayRow,
10472        position: Option<Anchor>,
10473        clicked_point: gpui::Point<Pixels>,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        let source = self
10478            .buffer
10479            .read(cx)
10480            .snapshot(cx)
10481            .anchor_before(Point::new(display_row.0, 0u32));
10482
10483        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10484
10485        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10486            self,
10487            source,
10488            clicked_point,
10489            context_menu,
10490            window,
10491            cx,
10492        );
10493    }
10494
10495    fn add_edit_breakpoint_block(
10496        &mut self,
10497        anchor: Anchor,
10498        breakpoint: &Breakpoint,
10499        edit_action: BreakpointPromptEditAction,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        let weak_editor = cx.weak_entity();
10504        let bp_prompt = cx.new(|cx| {
10505            BreakpointPromptEditor::new(
10506                weak_editor,
10507                anchor,
10508                breakpoint.clone(),
10509                edit_action,
10510                window,
10511                cx,
10512            )
10513        });
10514
10515        let height = bp_prompt.update(cx, |this, cx| {
10516            this.prompt
10517                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10518        });
10519        let cloned_prompt = bp_prompt.clone();
10520        let blocks = vec![BlockProperties {
10521            style: BlockStyle::Sticky,
10522            placement: BlockPlacement::Above(anchor),
10523            height: Some(height),
10524            render: Arc::new(move |cx| {
10525                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10526                cloned_prompt.clone().into_any_element()
10527            }),
10528            priority: 0,
10529        }];
10530
10531        let focus_handle = bp_prompt.focus_handle(cx);
10532        window.focus(&focus_handle);
10533
10534        let block_ids = self.insert_blocks(blocks, None, cx);
10535        bp_prompt.update(cx, |prompt, _| {
10536            prompt.add_block_ids(block_ids);
10537        });
10538    }
10539
10540    pub(crate) fn breakpoint_at_row(
10541        &self,
10542        row: u32,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) -> Option<(Anchor, Breakpoint)> {
10546        let snapshot = self.snapshot(window, cx);
10547        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10548
10549        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10550    }
10551
10552    pub(crate) fn breakpoint_at_anchor(
10553        &self,
10554        breakpoint_position: Anchor,
10555        snapshot: &EditorSnapshot,
10556        cx: &mut Context<Self>,
10557    ) -> Option<(Anchor, Breakpoint)> {
10558        let buffer = self
10559            .buffer
10560            .read(cx)
10561            .buffer_for_anchor(breakpoint_position, cx)?;
10562
10563        let enclosing_excerpt = breakpoint_position.excerpt_id;
10564        let buffer_snapshot = buffer.read(cx).snapshot();
10565
10566        let row = buffer_snapshot
10567            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10568            .row;
10569
10570        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10571        let anchor_end = snapshot
10572            .buffer_snapshot
10573            .anchor_after(Point::new(row, line_len));
10574
10575        self.breakpoint_store
10576            .as_ref()?
10577            .read_with(cx, |breakpoint_store, cx| {
10578                breakpoint_store
10579                    .breakpoints(
10580                        &buffer,
10581                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10582                        &buffer_snapshot,
10583                        cx,
10584                    )
10585                    .next()
10586                    .and_then(|(bp, _)| {
10587                        let breakpoint_row = buffer_snapshot
10588                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10589                            .row;
10590
10591                        if breakpoint_row == row {
10592                            snapshot
10593                                .buffer_snapshot
10594                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10595                                .map(|position| (position, bp.bp.clone()))
10596                        } else {
10597                            None
10598                        }
10599                    })
10600            })
10601    }
10602
10603    pub fn edit_log_breakpoint(
10604        &mut self,
10605        _: &EditLogBreakpoint,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10610            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10611                message: None,
10612                state: BreakpointState::Enabled,
10613                condition: None,
10614                hit_condition: None,
10615            });
10616
10617            self.add_edit_breakpoint_block(
10618                anchor,
10619                &breakpoint,
10620                BreakpointPromptEditAction::Log,
10621                window,
10622                cx,
10623            );
10624        }
10625    }
10626
10627    fn breakpoints_at_cursors(
10628        &self,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10632        let snapshot = self.snapshot(window, cx);
10633        let cursors = self
10634            .selections
10635            .disjoint_anchors()
10636            .iter()
10637            .map(|selection| {
10638                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10639
10640                let breakpoint_position = self
10641                    .breakpoint_at_row(cursor_position.row, window, cx)
10642                    .map(|bp| bp.0)
10643                    .unwrap_or_else(|| {
10644                        snapshot
10645                            .display_snapshot
10646                            .buffer_snapshot
10647                            .anchor_after(Point::new(cursor_position.row, 0))
10648                    });
10649
10650                let breakpoint = self
10651                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10652                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10653
10654                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10655            })
10656            // 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.
10657            .collect::<HashMap<Anchor, _>>();
10658
10659        cursors.into_iter().collect()
10660    }
10661
10662    pub fn enable_breakpoint(
10663        &mut self,
10664        _: &crate::actions::EnableBreakpoint,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10669            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10670                continue;
10671            };
10672            self.edit_breakpoint_at_anchor(
10673                anchor,
10674                breakpoint,
10675                BreakpointEditAction::InvertState,
10676                cx,
10677            );
10678        }
10679    }
10680
10681    pub fn disable_breakpoint(
10682        &mut self,
10683        _: &crate::actions::DisableBreakpoint,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686    ) {
10687        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10688            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10689                continue;
10690            };
10691            self.edit_breakpoint_at_anchor(
10692                anchor,
10693                breakpoint,
10694                BreakpointEditAction::InvertState,
10695                cx,
10696            );
10697        }
10698    }
10699
10700    pub fn toggle_breakpoint(
10701        &mut self,
10702        _: &crate::actions::ToggleBreakpoint,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10707            if let Some(breakpoint) = breakpoint {
10708                self.edit_breakpoint_at_anchor(
10709                    anchor,
10710                    breakpoint,
10711                    BreakpointEditAction::Toggle,
10712                    cx,
10713                );
10714            } else {
10715                self.edit_breakpoint_at_anchor(
10716                    anchor,
10717                    Breakpoint::new_standard(),
10718                    BreakpointEditAction::Toggle,
10719                    cx,
10720                );
10721            }
10722        }
10723    }
10724
10725    pub fn edit_breakpoint_at_anchor(
10726        &mut self,
10727        breakpoint_position: Anchor,
10728        breakpoint: Breakpoint,
10729        edit_action: BreakpointEditAction,
10730        cx: &mut Context<Self>,
10731    ) {
10732        let Some(breakpoint_store) = &self.breakpoint_store else {
10733            return;
10734        };
10735
10736        let Some(buffer) = self
10737            .buffer
10738            .read(cx)
10739            .buffer_for_anchor(breakpoint_position, cx)
10740        else {
10741            return;
10742        };
10743
10744        breakpoint_store.update(cx, |breakpoint_store, cx| {
10745            breakpoint_store.toggle_breakpoint(
10746                buffer,
10747                BreakpointWithPosition {
10748                    position: breakpoint_position.text_anchor,
10749                    bp: breakpoint,
10750                },
10751                edit_action,
10752                cx,
10753            );
10754        });
10755
10756        cx.notify();
10757    }
10758
10759    #[cfg(any(test, feature = "test-support"))]
10760    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10761        self.breakpoint_store.clone()
10762    }
10763
10764    pub fn prepare_restore_change(
10765        &self,
10766        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10767        hunk: &MultiBufferDiffHunk,
10768        cx: &mut App,
10769    ) -> Option<()> {
10770        if hunk.is_created_file() {
10771            return None;
10772        }
10773        let buffer = self.buffer.read(cx);
10774        let diff = buffer.diff_for(hunk.buffer_id)?;
10775        let buffer = buffer.buffer(hunk.buffer_id)?;
10776        let buffer = buffer.read(cx);
10777        let original_text = diff
10778            .read(cx)
10779            .base_text()
10780            .as_rope()
10781            .slice(hunk.diff_base_byte_range.clone());
10782        let buffer_snapshot = buffer.snapshot();
10783        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10784        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10785            probe
10786                .0
10787                .start
10788                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10789                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10790        }) {
10791            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10792            Some(())
10793        } else {
10794            None
10795        }
10796    }
10797
10798    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10799        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10800    }
10801
10802    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10803        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10804    }
10805
10806    fn manipulate_lines<M>(
10807        &mut self,
10808        window: &mut Window,
10809        cx: &mut Context<Self>,
10810        mut manipulate: M,
10811    ) where
10812        M: FnMut(&str) -> LineManipulationResult,
10813    {
10814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10815
10816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10817        let buffer = self.buffer.read(cx).snapshot(cx);
10818
10819        let mut edits = Vec::new();
10820
10821        let selections = self.selections.all::<Point>(cx);
10822        let mut selections = selections.iter().peekable();
10823        let mut contiguous_row_selections = Vec::new();
10824        let mut new_selections = Vec::new();
10825        let mut added_lines = 0;
10826        let mut removed_lines = 0;
10827
10828        while let Some(selection) = selections.next() {
10829            let (start_row, end_row) = consume_contiguous_rows(
10830                &mut contiguous_row_selections,
10831                selection,
10832                &display_map,
10833                &mut selections,
10834            );
10835
10836            let start_point = Point::new(start_row.0, 0);
10837            let end_point = Point::new(
10838                end_row.previous_row().0,
10839                buffer.line_len(end_row.previous_row()),
10840            );
10841            let text = buffer
10842                .text_for_range(start_point..end_point)
10843                .collect::<String>();
10844
10845            let LineManipulationResult {
10846                new_text,
10847                line_count_before,
10848                line_count_after,
10849            } = manipulate(&text);
10850
10851            edits.push((start_point..end_point, new_text));
10852
10853            // Selections must change based on added and removed line count
10854            let start_row =
10855                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10856            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10857            new_selections.push(Selection {
10858                id: selection.id,
10859                start: start_row,
10860                end: end_row,
10861                goal: SelectionGoal::None,
10862                reversed: selection.reversed,
10863            });
10864
10865            if line_count_after > line_count_before {
10866                added_lines += line_count_after - line_count_before;
10867            } else if line_count_before > line_count_after {
10868                removed_lines += line_count_before - line_count_after;
10869            }
10870        }
10871
10872        self.transact(window, cx, |this, window, cx| {
10873            let buffer = this.buffer.update(cx, |buffer, cx| {
10874                buffer.edit(edits, None, cx);
10875                buffer.snapshot(cx)
10876            });
10877
10878            // Recalculate offsets on newly edited buffer
10879            let new_selections = new_selections
10880                .iter()
10881                .map(|s| {
10882                    let start_point = Point::new(s.start.0, 0);
10883                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10884                    Selection {
10885                        id: s.id,
10886                        start: buffer.point_to_offset(start_point),
10887                        end: buffer.point_to_offset(end_point),
10888                        goal: s.goal,
10889                        reversed: s.reversed,
10890                    }
10891                })
10892                .collect();
10893
10894            this.change_selections(Default::default(), window, cx, |s| {
10895                s.select(new_selections);
10896            });
10897
10898            this.request_autoscroll(Autoscroll::fit(), cx);
10899        });
10900    }
10901
10902    fn manipulate_immutable_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<&str>),
10909    {
10910        self.manipulate_lines(window, cx, |text| {
10911            let mut lines: Vec<&str> = text.split('\n').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    fn manipulate_mutable_lines<Fn>(
10925        &mut self,
10926        window: &mut Window,
10927        cx: &mut Context<Self>,
10928        mut callback: Fn,
10929    ) where
10930        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10931    {
10932        self.manipulate_lines(window, cx, |text| {
10933            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10934            let line_count_before = lines.len();
10935
10936            callback(&mut lines);
10937
10938            LineManipulationResult {
10939                new_text: lines.join("\n"),
10940                line_count_before,
10941                line_count_after: lines.len(),
10942            }
10943        });
10944    }
10945
10946    pub fn convert_indentation_to_spaces(
10947        &mut self,
10948        _: &ConvertIndentationToSpaces,
10949        window: &mut Window,
10950        cx: &mut Context<Self>,
10951    ) {
10952        let settings = self.buffer.read(cx).language_settings(cx);
10953        let tab_size = settings.tab_size.get() as usize;
10954
10955        self.manipulate_mutable_lines(window, cx, |lines| {
10956            // Allocates a reasonably sized scratch buffer once for the whole loop
10957            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10958            // Avoids recomputing spaces that could be inserted many times
10959            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10960                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10961                .collect();
10962
10963            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10964                let mut chars = line.as_ref().chars();
10965                let mut col = 0;
10966                let mut changed = false;
10967
10968                for ch in chars.by_ref() {
10969                    match ch {
10970                        ' ' => {
10971                            reindented_line.push(' ');
10972                            col += 1;
10973                        }
10974                        '\t' => {
10975                            // \t are converted to spaces depending on the current column
10976                            let spaces_len = tab_size - (col % tab_size);
10977                            reindented_line.extend(&space_cache[spaces_len - 1]);
10978                            col += spaces_len;
10979                            changed = true;
10980                        }
10981                        _ => {
10982                            // If we dont append before break, the character is consumed
10983                            reindented_line.push(ch);
10984                            break;
10985                        }
10986                    }
10987                }
10988
10989                if !changed {
10990                    reindented_line.clear();
10991                    continue;
10992                }
10993                // Append the rest of the line and replace old reference with new one
10994                reindented_line.extend(chars);
10995                *line = Cow::Owned(reindented_line.clone());
10996                reindented_line.clear();
10997            }
10998        });
10999    }
11000
11001    pub fn convert_indentation_to_tabs(
11002        &mut self,
11003        _: &ConvertIndentationToTabs,
11004        window: &mut Window,
11005        cx: &mut Context<Self>,
11006    ) {
11007        let settings = self.buffer.read(cx).language_settings(cx);
11008        let tab_size = settings.tab_size.get() as usize;
11009
11010        self.manipulate_mutable_lines(window, cx, |lines| {
11011            // Allocates a reasonably sized buffer once for the whole loop
11012            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11013            // Avoids recomputing spaces that could be inserted many times
11014            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11015                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11016                .collect();
11017
11018            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11019                let mut chars = line.chars();
11020                let mut spaces_count = 0;
11021                let mut first_non_indent_char = None;
11022                let mut changed = false;
11023
11024                for ch in chars.by_ref() {
11025                    match ch {
11026                        ' ' => {
11027                            // Keep track of spaces. Append \t when we reach tab_size
11028                            spaces_count += 1;
11029                            changed = true;
11030                            if spaces_count == tab_size {
11031                                reindented_line.push('\t');
11032                                spaces_count = 0;
11033                            }
11034                        }
11035                        '\t' => {
11036                            reindented_line.push('\t');
11037                            spaces_count = 0;
11038                        }
11039                        _ => {
11040                            // Dont append it yet, we might have remaining spaces
11041                            first_non_indent_char = Some(ch);
11042                            break;
11043                        }
11044                    }
11045                }
11046
11047                if !changed {
11048                    reindented_line.clear();
11049                    continue;
11050                }
11051                // Remaining spaces that didn't make a full tab stop
11052                if spaces_count > 0 {
11053                    reindented_line.extend(&space_cache[spaces_count - 1]);
11054                }
11055                // If we consume an extra character that was not indentation, add it back
11056                if let Some(extra_char) = first_non_indent_char {
11057                    reindented_line.push(extra_char);
11058                }
11059                // Append the rest of the line and replace old reference with new one
11060                reindented_line.extend(chars);
11061                *line = Cow::Owned(reindented_line.clone());
11062                reindented_line.clear();
11063            }
11064        });
11065    }
11066
11067    pub fn convert_to_upper_case(
11068        &mut self,
11069        _: &ConvertToUpperCase,
11070        window: &mut Window,
11071        cx: &mut Context<Self>,
11072    ) {
11073        self.manipulate_text(window, cx, |text| text.to_uppercase())
11074    }
11075
11076    pub fn convert_to_lower_case(
11077        &mut self,
11078        _: &ConvertToLowerCase,
11079        window: &mut Window,
11080        cx: &mut Context<Self>,
11081    ) {
11082        self.manipulate_text(window, cx, |text| text.to_lowercase())
11083    }
11084
11085    pub fn convert_to_title_case(
11086        &mut self,
11087        _: &ConvertToTitleCase,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| {
11092            text.split('\n')
11093                .map(|line| line.to_case(Case::Title))
11094                .join("\n")
11095        })
11096    }
11097
11098    pub fn convert_to_snake_case(
11099        &mut self,
11100        _: &ConvertToSnakeCase,
11101        window: &mut Window,
11102        cx: &mut Context<Self>,
11103    ) {
11104        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11105    }
11106
11107    pub fn convert_to_kebab_case(
11108        &mut self,
11109        _: &ConvertToKebabCase,
11110        window: &mut Window,
11111        cx: &mut Context<Self>,
11112    ) {
11113        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11114    }
11115
11116    pub fn convert_to_upper_camel_case(
11117        &mut self,
11118        _: &ConvertToUpperCamelCase,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        self.manipulate_text(window, cx, |text| {
11123            text.split('\n')
11124                .map(|line| line.to_case(Case::UpperCamel))
11125                .join("\n")
11126        })
11127    }
11128
11129    pub fn convert_to_lower_camel_case(
11130        &mut self,
11131        _: &ConvertToLowerCamelCase,
11132        window: &mut Window,
11133        cx: &mut Context<Self>,
11134    ) {
11135        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11136    }
11137
11138    pub fn convert_to_opposite_case(
11139        &mut self,
11140        _: &ConvertToOppositeCase,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143    ) {
11144        self.manipulate_text(window, cx, |text| {
11145            text.chars()
11146                .fold(String::with_capacity(text.len()), |mut t, c| {
11147                    if c.is_uppercase() {
11148                        t.extend(c.to_lowercase());
11149                    } else {
11150                        t.extend(c.to_uppercase());
11151                    }
11152                    t
11153                })
11154        })
11155    }
11156
11157    pub fn convert_to_sentence_case(
11158        &mut self,
11159        _: &ConvertToSentenceCase,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162    ) {
11163        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11164    }
11165
11166    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11167        self.manipulate_text(window, cx, |text| {
11168            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11169            if has_upper_case_characters {
11170                text.to_lowercase()
11171            } else {
11172                text.to_uppercase()
11173            }
11174        })
11175    }
11176
11177    pub fn convert_to_rot13(
11178        &mut self,
11179        _: &ConvertToRot13,
11180        window: &mut Window,
11181        cx: &mut Context<Self>,
11182    ) {
11183        self.manipulate_text(window, cx, |text| {
11184            text.chars()
11185                .map(|c| match c {
11186                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11187                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11188                    _ => c,
11189                })
11190                .collect()
11191        })
11192    }
11193
11194    pub fn convert_to_rot47(
11195        &mut self,
11196        _: &ConvertToRot47,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.manipulate_text(window, cx, |text| {
11201            text.chars()
11202                .map(|c| {
11203                    let code_point = c as u32;
11204                    if code_point >= 33 && code_point <= 126 {
11205                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11206                    }
11207                    c
11208                })
11209                .collect()
11210        })
11211    }
11212
11213    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11214    where
11215        Fn: FnMut(&str) -> String,
11216    {
11217        let buffer = self.buffer.read(cx).snapshot(cx);
11218
11219        let mut new_selections = Vec::new();
11220        let mut edits = Vec::new();
11221        let mut selection_adjustment = 0i32;
11222
11223        for selection in self.selections.all::<usize>(cx) {
11224            let selection_is_empty = selection.is_empty();
11225
11226            let (start, end) = if selection_is_empty {
11227                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11228                (word_range.start, word_range.end)
11229            } else {
11230                (selection.start, selection.end)
11231            };
11232
11233            let text = buffer.text_for_range(start..end).collect::<String>();
11234            let old_length = text.len() as i32;
11235            let text = callback(&text);
11236
11237            new_selections.push(Selection {
11238                start: (start as i32 - selection_adjustment) as usize,
11239                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11240                goal: SelectionGoal::None,
11241                ..selection
11242            });
11243
11244            selection_adjustment += old_length - text.len() as i32;
11245
11246            edits.push((start..end, text));
11247        }
11248
11249        self.transact(window, cx, |this, window, cx| {
11250            this.buffer.update(cx, |buffer, cx| {
11251                buffer.edit(edits, None, cx);
11252            });
11253
11254            this.change_selections(Default::default(), window, cx, |s| {
11255                s.select(new_selections);
11256            });
11257
11258            this.request_autoscroll(Autoscroll::fit(), cx);
11259        });
11260    }
11261
11262    pub fn move_selection_on_drop(
11263        &mut self,
11264        selection: &Selection<Anchor>,
11265        target: DisplayPoint,
11266        is_cut: bool,
11267        window: &mut Window,
11268        cx: &mut Context<Self>,
11269    ) {
11270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11271        let buffer = &display_map.buffer_snapshot;
11272        let mut edits = Vec::new();
11273        let insert_point = display_map
11274            .clip_point(target, Bias::Left)
11275            .to_point(&display_map);
11276        let text = buffer
11277            .text_for_range(selection.start..selection.end)
11278            .collect::<String>();
11279        if is_cut {
11280            edits.push(((selection.start..selection.end), String::new()));
11281        }
11282        let insert_anchor = buffer.anchor_before(insert_point);
11283        edits.push(((insert_anchor..insert_anchor), text));
11284        let last_edit_start = insert_anchor.bias_left(buffer);
11285        let last_edit_end = insert_anchor.bias_right(buffer);
11286        self.transact(window, cx, |this, window, cx| {
11287            this.buffer.update(cx, |buffer, cx| {
11288                buffer.edit(edits, None, cx);
11289            });
11290            this.change_selections(Default::default(), window, cx, |s| {
11291                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11292            });
11293        });
11294    }
11295
11296    pub fn clear_selection_drag_state(&mut self) {
11297        self.selection_drag_state = SelectionDragState::None;
11298    }
11299
11300    pub fn duplicate(
11301        &mut self,
11302        upwards: bool,
11303        whole_lines: bool,
11304        window: &mut Window,
11305        cx: &mut Context<Self>,
11306    ) {
11307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11308
11309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11310        let buffer = &display_map.buffer_snapshot;
11311        let selections = self.selections.all::<Point>(cx);
11312
11313        let mut edits = Vec::new();
11314        let mut selections_iter = selections.iter().peekable();
11315        while let Some(selection) = selections_iter.next() {
11316            let mut rows = selection.spanned_rows(false, &display_map);
11317            // duplicate line-wise
11318            if whole_lines || selection.start == selection.end {
11319                // Avoid duplicating the same lines twice.
11320                while let Some(next_selection) = selections_iter.peek() {
11321                    let next_rows = next_selection.spanned_rows(false, &display_map);
11322                    if next_rows.start < rows.end {
11323                        rows.end = next_rows.end;
11324                        selections_iter.next().unwrap();
11325                    } else {
11326                        break;
11327                    }
11328                }
11329
11330                // Copy the text from the selected row region and splice it either at the start
11331                // or end of the region.
11332                let start = Point::new(rows.start.0, 0);
11333                let end = Point::new(
11334                    rows.end.previous_row().0,
11335                    buffer.line_len(rows.end.previous_row()),
11336                );
11337                let text = buffer
11338                    .text_for_range(start..end)
11339                    .chain(Some("\n"))
11340                    .collect::<String>();
11341                let insert_location = if upwards {
11342                    Point::new(rows.end.0, 0)
11343                } else {
11344                    start
11345                };
11346                edits.push((insert_location..insert_location, text));
11347            } else {
11348                // duplicate character-wise
11349                let start = selection.start;
11350                let end = selection.end;
11351                let text = buffer.text_for_range(start..end).collect::<String>();
11352                edits.push((selection.end..selection.end, text));
11353            }
11354        }
11355
11356        self.transact(window, cx, |this, _, cx| {
11357            this.buffer.update(cx, |buffer, cx| {
11358                buffer.edit(edits, None, cx);
11359            });
11360
11361            this.request_autoscroll(Autoscroll::fit(), cx);
11362        });
11363    }
11364
11365    pub fn duplicate_line_up(
11366        &mut self,
11367        _: &DuplicateLineUp,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) {
11371        self.duplicate(true, true, window, cx);
11372    }
11373
11374    pub fn duplicate_line_down(
11375        &mut self,
11376        _: &DuplicateLineDown,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379    ) {
11380        self.duplicate(false, true, window, cx);
11381    }
11382
11383    pub fn duplicate_selection(
11384        &mut self,
11385        _: &DuplicateSelection,
11386        window: &mut Window,
11387        cx: &mut Context<Self>,
11388    ) {
11389        self.duplicate(false, false, window, cx);
11390    }
11391
11392    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11394        if self.mode.is_single_line() {
11395            cx.propagate();
11396            return;
11397        }
11398
11399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11400        let buffer = self.buffer.read(cx).snapshot(cx);
11401
11402        let mut edits = Vec::new();
11403        let mut unfold_ranges = Vec::new();
11404        let mut refold_creases = Vec::new();
11405
11406        let selections = self.selections.all::<Point>(cx);
11407        let mut selections = selections.iter().peekable();
11408        let mut contiguous_row_selections = Vec::new();
11409        let mut new_selections = Vec::new();
11410
11411        while let Some(selection) = selections.next() {
11412            // Find all the selections that span a contiguous row range
11413            let (start_row, end_row) = consume_contiguous_rows(
11414                &mut contiguous_row_selections,
11415                selection,
11416                &display_map,
11417                &mut selections,
11418            );
11419
11420            // Move the text spanned by the row range to be before the line preceding the row range
11421            if start_row.0 > 0 {
11422                let range_to_move = Point::new(
11423                    start_row.previous_row().0,
11424                    buffer.line_len(start_row.previous_row()),
11425                )
11426                    ..Point::new(
11427                        end_row.previous_row().0,
11428                        buffer.line_len(end_row.previous_row()),
11429                    );
11430                let insertion_point = display_map
11431                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11432                    .0;
11433
11434                // Don't move lines across excerpts
11435                if buffer
11436                    .excerpt_containing(insertion_point..range_to_move.end)
11437                    .is_some()
11438                {
11439                    let text = buffer
11440                        .text_for_range(range_to_move.clone())
11441                        .flat_map(|s| s.chars())
11442                        .skip(1)
11443                        .chain(['\n'])
11444                        .collect::<String>();
11445
11446                    edits.push((
11447                        buffer.anchor_after(range_to_move.start)
11448                            ..buffer.anchor_before(range_to_move.end),
11449                        String::new(),
11450                    ));
11451                    let insertion_anchor = buffer.anchor_after(insertion_point);
11452                    edits.push((insertion_anchor..insertion_anchor, text));
11453
11454                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11455
11456                    // Move selections up
11457                    new_selections.extend(contiguous_row_selections.drain(..).map(
11458                        |mut selection| {
11459                            selection.start.row -= row_delta;
11460                            selection.end.row -= row_delta;
11461                            selection
11462                        },
11463                    ));
11464
11465                    // Move folds up
11466                    unfold_ranges.push(range_to_move.clone());
11467                    for fold in display_map.folds_in_range(
11468                        buffer.anchor_before(range_to_move.start)
11469                            ..buffer.anchor_after(range_to_move.end),
11470                    ) {
11471                        let mut start = fold.range.start.to_point(&buffer);
11472                        let mut end = fold.range.end.to_point(&buffer);
11473                        start.row -= row_delta;
11474                        end.row -= row_delta;
11475                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11476                    }
11477                }
11478            }
11479
11480            // If we didn't move line(s), preserve the existing selections
11481            new_selections.append(&mut contiguous_row_selections);
11482        }
11483
11484        self.transact(window, cx, |this, window, cx| {
11485            this.unfold_ranges(&unfold_ranges, true, true, cx);
11486            this.buffer.update(cx, |buffer, cx| {
11487                for (range, text) in edits {
11488                    buffer.edit([(range, text)], None, cx);
11489                }
11490            });
11491            this.fold_creases(refold_creases, true, window, cx);
11492            this.change_selections(Default::default(), window, cx, |s| {
11493                s.select(new_selections);
11494            })
11495        });
11496    }
11497
11498    pub fn move_line_down(
11499        &mut self,
11500        _: &MoveLineDown,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505        if self.mode.is_single_line() {
11506            cx.propagate();
11507            return;
11508        }
11509
11510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11511        let buffer = self.buffer.read(cx).snapshot(cx);
11512
11513        let mut edits = Vec::new();
11514        let mut unfold_ranges = Vec::new();
11515        let mut refold_creases = Vec::new();
11516
11517        let selections = self.selections.all::<Point>(cx);
11518        let mut selections = selections.iter().peekable();
11519        let mut contiguous_row_selections = Vec::new();
11520        let mut new_selections = Vec::new();
11521
11522        while let Some(selection) = selections.next() {
11523            // Find all the selections that span a contiguous row range
11524            let (start_row, end_row) = consume_contiguous_rows(
11525                &mut contiguous_row_selections,
11526                selection,
11527                &display_map,
11528                &mut selections,
11529            );
11530
11531            // Move the text spanned by the row range to be after the last line of the row range
11532            if end_row.0 <= buffer.max_point().row {
11533                let range_to_move =
11534                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11535                let insertion_point = display_map
11536                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11537                    .0;
11538
11539                // Don't move lines across excerpt boundaries
11540                if buffer
11541                    .excerpt_containing(range_to_move.start..insertion_point)
11542                    .is_some()
11543                {
11544                    let mut text = String::from("\n");
11545                    text.extend(buffer.text_for_range(range_to_move.clone()));
11546                    text.pop(); // Drop trailing newline
11547                    edits.push((
11548                        buffer.anchor_after(range_to_move.start)
11549                            ..buffer.anchor_before(range_to_move.end),
11550                        String::new(),
11551                    ));
11552                    let insertion_anchor = buffer.anchor_after(insertion_point);
11553                    edits.push((insertion_anchor..insertion_anchor, text));
11554
11555                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11556
11557                    // Move selections down
11558                    new_selections.extend(contiguous_row_selections.drain(..).map(
11559                        |mut selection| {
11560                            selection.start.row += row_delta;
11561                            selection.end.row += row_delta;
11562                            selection
11563                        },
11564                    ));
11565
11566                    // Move folds down
11567                    unfold_ranges.push(range_to_move.clone());
11568                    for fold in display_map.folds_in_range(
11569                        buffer.anchor_before(range_to_move.start)
11570                            ..buffer.anchor_after(range_to_move.end),
11571                    ) {
11572                        let mut start = fold.range.start.to_point(&buffer);
11573                        let mut end = fold.range.end.to_point(&buffer);
11574                        start.row += row_delta;
11575                        end.row += row_delta;
11576                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11577                    }
11578                }
11579            }
11580
11581            // If we didn't move line(s), preserve the existing selections
11582            new_selections.append(&mut contiguous_row_selections);
11583        }
11584
11585        self.transact(window, cx, |this, window, cx| {
11586            this.unfold_ranges(&unfold_ranges, true, true, cx);
11587            this.buffer.update(cx, |buffer, cx| {
11588                for (range, text) in edits {
11589                    buffer.edit([(range, text)], None, cx);
11590                }
11591            });
11592            this.fold_creases(refold_creases, true, window, cx);
11593            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11594        });
11595    }
11596
11597    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11599        let text_layout_details = &self.text_layout_details(window);
11600        self.transact(window, cx, |this, window, cx| {
11601            let edits = this.change_selections(Default::default(), window, cx, |s| {
11602                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11603                s.move_with(|display_map, selection| {
11604                    if !selection.is_empty() {
11605                        return;
11606                    }
11607
11608                    let mut head = selection.head();
11609                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11610                    if head.column() == display_map.line_len(head.row()) {
11611                        transpose_offset = display_map
11612                            .buffer_snapshot
11613                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11614                    }
11615
11616                    if transpose_offset == 0 {
11617                        return;
11618                    }
11619
11620                    *head.column_mut() += 1;
11621                    head = display_map.clip_point(head, Bias::Right);
11622                    let goal = SelectionGoal::HorizontalPosition(
11623                        display_map
11624                            .x_for_display_point(head, text_layout_details)
11625                            .into(),
11626                    );
11627                    selection.collapse_to(head, goal);
11628
11629                    let transpose_start = display_map
11630                        .buffer_snapshot
11631                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11632                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11633                        let transpose_end = display_map
11634                            .buffer_snapshot
11635                            .clip_offset(transpose_offset + 1, Bias::Right);
11636                        if let Some(ch) =
11637                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11638                        {
11639                            edits.push((transpose_start..transpose_offset, String::new()));
11640                            edits.push((transpose_end..transpose_end, ch.to_string()));
11641                        }
11642                    }
11643                });
11644                edits
11645            });
11646            this.buffer
11647                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11648            let selections = this.selections.all::<usize>(cx);
11649            this.change_selections(Default::default(), window, cx, |s| {
11650                s.select(selections);
11651            });
11652        });
11653    }
11654
11655    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11657        if self.mode.is_single_line() {
11658            cx.propagate();
11659            return;
11660        }
11661
11662        self.rewrap_impl(RewrapOptions::default(), cx)
11663    }
11664
11665    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11666        let buffer = self.buffer.read(cx).snapshot(cx);
11667        let selections = self.selections.all::<Point>(cx);
11668
11669        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11670        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11671            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11672                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11673                .peekable();
11674
11675            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11676                row
11677            } else {
11678                return Vec::new();
11679            };
11680
11681            let language_settings = buffer.language_settings_at(selection.head(), cx);
11682            let language_scope = buffer.language_scope_at(selection.head());
11683
11684            let indent_and_prefix_for_row =
11685                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11686                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11687                    let (comment_prefix, rewrap_prefix) =
11688                        if let Some(language_scope) = &language_scope {
11689                            let indent_end = Point::new(row, indent.len);
11690                            let comment_prefix = language_scope
11691                                .line_comment_prefixes()
11692                                .iter()
11693                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11694                                .map(|prefix| prefix.to_string());
11695                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11696                            let line_text_after_indent = buffer
11697                                .text_for_range(indent_end..line_end)
11698                                .collect::<String>();
11699                            let rewrap_prefix = language_scope
11700                                .rewrap_prefixes()
11701                                .iter()
11702                                .find_map(|prefix_regex| {
11703                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11704                                        if mat.start() == 0 {
11705                                            Some(mat.as_str().to_string())
11706                                        } else {
11707                                            None
11708                                        }
11709                                    })
11710                                })
11711                                .flatten();
11712                            (comment_prefix, rewrap_prefix)
11713                        } else {
11714                            (None, None)
11715                        };
11716                    (indent, comment_prefix, rewrap_prefix)
11717                };
11718
11719            let mut ranges = Vec::new();
11720            let from_empty_selection = selection.is_empty();
11721
11722            let mut current_range_start = first_row;
11723            let mut prev_row = first_row;
11724            let (
11725                mut current_range_indent,
11726                mut current_range_comment_prefix,
11727                mut current_range_rewrap_prefix,
11728            ) = indent_and_prefix_for_row(first_row);
11729
11730            for row in non_blank_rows_iter.skip(1) {
11731                let has_paragraph_break = row > prev_row + 1;
11732
11733                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11734                    indent_and_prefix_for_row(row);
11735
11736                let has_indent_change = row_indent != current_range_indent;
11737                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11738
11739                let has_boundary_change = has_comment_change
11740                    || row_rewrap_prefix.is_some()
11741                    || (has_indent_change && current_range_comment_prefix.is_some());
11742
11743                if has_paragraph_break || has_boundary_change {
11744                    ranges.push((
11745                        language_settings.clone(),
11746                        Point::new(current_range_start, 0)
11747                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11748                        current_range_indent,
11749                        current_range_comment_prefix.clone(),
11750                        current_range_rewrap_prefix.clone(),
11751                        from_empty_selection,
11752                    ));
11753                    current_range_start = row;
11754                    current_range_indent = row_indent;
11755                    current_range_comment_prefix = row_comment_prefix;
11756                    current_range_rewrap_prefix = row_rewrap_prefix;
11757                }
11758                prev_row = row;
11759            }
11760
11761            ranges.push((
11762                language_settings.clone(),
11763                Point::new(current_range_start, 0)
11764                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11765                current_range_indent,
11766                current_range_comment_prefix,
11767                current_range_rewrap_prefix,
11768                from_empty_selection,
11769            ));
11770
11771            ranges
11772        });
11773
11774        let mut edits = Vec::new();
11775        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11776
11777        for (
11778            language_settings,
11779            wrap_range,
11780            indent_size,
11781            comment_prefix,
11782            rewrap_prefix,
11783            from_empty_selection,
11784        ) in wrap_ranges
11785        {
11786            let mut start_row = wrap_range.start.row;
11787            let mut end_row = wrap_range.end.row;
11788
11789            // Skip selections that overlap with a range that has already been rewrapped.
11790            let selection_range = start_row..end_row;
11791            if rewrapped_row_ranges
11792                .iter()
11793                .any(|range| range.overlaps(&selection_range))
11794            {
11795                continue;
11796            }
11797
11798            let tab_size = language_settings.tab_size;
11799
11800            let indent_prefix = indent_size.chars().collect::<String>();
11801            let mut line_prefix = indent_prefix.clone();
11802            let mut inside_comment = false;
11803            if let Some(prefix) = &comment_prefix {
11804                line_prefix.push_str(prefix);
11805                inside_comment = true;
11806            }
11807            if let Some(prefix) = &rewrap_prefix {
11808                line_prefix.push_str(prefix);
11809            }
11810
11811            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11812                RewrapBehavior::InComments => inside_comment,
11813                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11814                RewrapBehavior::Anywhere => true,
11815            };
11816
11817            let should_rewrap = options.override_language_settings
11818                || allow_rewrap_based_on_language
11819                || self.hard_wrap.is_some();
11820            if !should_rewrap {
11821                continue;
11822            }
11823
11824            if from_empty_selection {
11825                'expand_upwards: while start_row > 0 {
11826                    let prev_row = start_row - 1;
11827                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11828                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11829                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11830                    {
11831                        start_row = prev_row;
11832                    } else {
11833                        break 'expand_upwards;
11834                    }
11835                }
11836
11837                'expand_downwards: while end_row < buffer.max_point().row {
11838                    let next_row = end_row + 1;
11839                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11840                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11841                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11842                    {
11843                        end_row = next_row;
11844                    } else {
11845                        break 'expand_downwards;
11846                    }
11847                }
11848            }
11849
11850            let start = Point::new(start_row, 0);
11851            let start_offset = start.to_offset(&buffer);
11852            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11853            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11854            let Some(lines_without_prefixes) = selection_text
11855                .lines()
11856                .enumerate()
11857                .map(|(ix, line)| {
11858                    let line_trimmed = line.trim_start();
11859                    if rewrap_prefix.is_some() && ix > 0 {
11860                        Ok(line_trimmed)
11861                    } else {
11862                        line_trimmed
11863                            .strip_prefix(&line_prefix.trim_start())
11864                            .with_context(|| {
11865                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11866                            })
11867                    }
11868                })
11869                .collect::<Result<Vec<_>, _>>()
11870                .log_err()
11871            else {
11872                continue;
11873            };
11874
11875            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11876                buffer
11877                    .language_settings_at(Point::new(start_row, 0), cx)
11878                    .preferred_line_length as usize
11879            });
11880
11881            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11882                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11883            } else {
11884                line_prefix.clone()
11885            };
11886
11887            let wrapped_text = wrap_with_prefix(
11888                line_prefix,
11889                subsequent_lines_prefix,
11890                lines_without_prefixes.join("\n"),
11891                wrap_column,
11892                tab_size,
11893                options.preserve_existing_whitespace,
11894            );
11895
11896            // TODO: should always use char-based diff while still supporting cursor behavior that
11897            // matches vim.
11898            let mut diff_options = DiffOptions::default();
11899            if options.override_language_settings {
11900                diff_options.max_word_diff_len = 0;
11901                diff_options.max_word_diff_line_count = 0;
11902            } else {
11903                diff_options.max_word_diff_len = usize::MAX;
11904                diff_options.max_word_diff_line_count = usize::MAX;
11905            }
11906
11907            for (old_range, new_text) in
11908                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11909            {
11910                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11911                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11912                edits.push((edit_start..edit_end, new_text));
11913            }
11914
11915            rewrapped_row_ranges.push(start_row..=end_row);
11916        }
11917
11918        self.buffer
11919            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11920    }
11921
11922    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11923        let mut text = String::new();
11924        let buffer = self.buffer.read(cx).snapshot(cx);
11925        let mut selections = self.selections.all::<Point>(cx);
11926        let mut clipboard_selections = Vec::with_capacity(selections.len());
11927        {
11928            let max_point = buffer.max_point();
11929            let mut is_first = true;
11930            for selection in &mut selections {
11931                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11932                if is_entire_line {
11933                    selection.start = Point::new(selection.start.row, 0);
11934                    if !selection.is_empty() && selection.end.column == 0 {
11935                        selection.end = cmp::min(max_point, selection.end);
11936                    } else {
11937                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11938                    }
11939                    selection.goal = SelectionGoal::None;
11940                }
11941                if is_first {
11942                    is_first = false;
11943                } else {
11944                    text += "\n";
11945                }
11946                let mut len = 0;
11947                for chunk in buffer.text_for_range(selection.start..selection.end) {
11948                    text.push_str(chunk);
11949                    len += chunk.len();
11950                }
11951                clipboard_selections.push(ClipboardSelection {
11952                    len,
11953                    is_entire_line,
11954                    first_line_indent: buffer
11955                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11956                        .len,
11957                });
11958            }
11959        }
11960
11961        self.transact(window, cx, |this, window, cx| {
11962            this.change_selections(Default::default(), window, cx, |s| {
11963                s.select(selections);
11964            });
11965            this.insert("", window, cx);
11966        });
11967        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11968    }
11969
11970    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11972        let item = self.cut_common(window, cx);
11973        cx.write_to_clipboard(item);
11974    }
11975
11976    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11978        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11979            s.move_with(|snapshot, sel| {
11980                if sel.is_empty() {
11981                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11982                }
11983            });
11984        });
11985        let item = self.cut_common(window, cx);
11986        cx.set_global(KillRing(item))
11987    }
11988
11989    pub fn kill_ring_yank(
11990        &mut self,
11991        _: &KillRingYank,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11996        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11997            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11998                (kill_ring.text().to_string(), kill_ring.metadata_json())
11999            } else {
12000                return;
12001            }
12002        } else {
12003            return;
12004        };
12005        self.do_paste(&text, metadata, false, window, cx);
12006    }
12007
12008    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12009        self.do_copy(true, cx);
12010    }
12011
12012    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12013        self.do_copy(false, cx);
12014    }
12015
12016    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12017        let selections = self.selections.all::<Point>(cx);
12018        let buffer = self.buffer.read(cx).read(cx);
12019        let mut text = String::new();
12020
12021        let mut clipboard_selections = Vec::with_capacity(selections.len());
12022        {
12023            let max_point = buffer.max_point();
12024            let mut is_first = true;
12025            for selection in &selections {
12026                let mut start = selection.start;
12027                let mut end = selection.end;
12028                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12029                if is_entire_line {
12030                    start = Point::new(start.row, 0);
12031                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12032                }
12033
12034                let mut trimmed_selections = Vec::new();
12035                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12036                    let row = MultiBufferRow(start.row);
12037                    let first_indent = buffer.indent_size_for_line(row);
12038                    if first_indent.len == 0 || start.column > first_indent.len {
12039                        trimmed_selections.push(start..end);
12040                    } else {
12041                        trimmed_selections.push(
12042                            Point::new(row.0, first_indent.len)
12043                                ..Point::new(row.0, buffer.line_len(row)),
12044                        );
12045                        for row in start.row + 1..=end.row {
12046                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12047                            if row == end.row {
12048                                line_len = end.column;
12049                            }
12050                            if line_len == 0 {
12051                                trimmed_selections
12052                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12053                                continue;
12054                            }
12055                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12056                            if row_indent_size.len >= first_indent.len {
12057                                trimmed_selections.push(
12058                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12059                                );
12060                            } else {
12061                                trimmed_selections.clear();
12062                                trimmed_selections.push(start..end);
12063                                break;
12064                            }
12065                        }
12066                    }
12067                } else {
12068                    trimmed_selections.push(start..end);
12069                }
12070
12071                for trimmed_range in trimmed_selections {
12072                    if is_first {
12073                        is_first = false;
12074                    } else {
12075                        text += "\n";
12076                    }
12077                    let mut len = 0;
12078                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12079                        text.push_str(chunk);
12080                        len += chunk.len();
12081                    }
12082                    clipboard_selections.push(ClipboardSelection {
12083                        len,
12084                        is_entire_line,
12085                        first_line_indent: buffer
12086                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12087                            .len,
12088                    });
12089                }
12090            }
12091        }
12092
12093        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12094            text,
12095            clipboard_selections,
12096        ));
12097    }
12098
12099    pub fn do_paste(
12100        &mut self,
12101        text: &String,
12102        clipboard_selections: Option<Vec<ClipboardSelection>>,
12103        handle_entire_lines: bool,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        if self.read_only(cx) {
12108            return;
12109        }
12110
12111        let clipboard_text = Cow::Borrowed(text);
12112
12113        self.transact(window, cx, |this, window, cx| {
12114            let had_active_edit_prediction = this.has_active_edit_prediction();
12115
12116            if let Some(mut clipboard_selections) = clipboard_selections {
12117                let old_selections = this.selections.all::<usize>(cx);
12118                let all_selections_were_entire_line =
12119                    clipboard_selections.iter().all(|s| s.is_entire_line);
12120                let first_selection_indent_column =
12121                    clipboard_selections.first().map(|s| s.first_line_indent);
12122                if clipboard_selections.len() != old_selections.len() {
12123                    clipboard_selections.drain(..);
12124                }
12125                let cursor_offset = this.selections.last::<usize>(cx).head();
12126                let mut auto_indent_on_paste = true;
12127
12128                this.buffer.update(cx, |buffer, cx| {
12129                    let snapshot = buffer.read(cx);
12130                    auto_indent_on_paste = snapshot
12131                        .language_settings_at(cursor_offset, cx)
12132                        .auto_indent_on_paste;
12133
12134                    let mut start_offset = 0;
12135                    let mut edits = Vec::new();
12136                    let mut original_indent_columns = Vec::new();
12137                    for (ix, selection) in old_selections.iter().enumerate() {
12138                        let to_insert;
12139                        let entire_line;
12140                        let original_indent_column;
12141                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12142                            let end_offset = start_offset + clipboard_selection.len;
12143                            to_insert = &clipboard_text[start_offset..end_offset];
12144                            entire_line = clipboard_selection.is_entire_line;
12145                            start_offset = end_offset + 1;
12146                            original_indent_column = Some(clipboard_selection.first_line_indent);
12147                        } else {
12148                            to_insert = clipboard_text.as_str();
12149                            entire_line = all_selections_were_entire_line;
12150                            original_indent_column = first_selection_indent_column
12151                        }
12152
12153                        // If the corresponding selection was empty when this slice of the
12154                        // clipboard text was written, then the entire line containing the
12155                        // selection was copied. If this selection is also currently empty,
12156                        // then paste the line before the current line of the buffer.
12157                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12158                            let column = selection.start.to_point(&snapshot).column as usize;
12159                            let line_start = selection.start - column;
12160                            line_start..line_start
12161                        } else {
12162                            selection.range()
12163                        };
12164
12165                        edits.push((range, to_insert));
12166                        original_indent_columns.push(original_indent_column);
12167                    }
12168                    drop(snapshot);
12169
12170                    buffer.edit(
12171                        edits,
12172                        if auto_indent_on_paste {
12173                            Some(AutoindentMode::Block {
12174                                original_indent_columns,
12175                            })
12176                        } else {
12177                            None
12178                        },
12179                        cx,
12180                    );
12181                });
12182
12183                let selections = this.selections.all::<usize>(cx);
12184                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12185            } else {
12186                this.insert(&clipboard_text, window, cx);
12187            }
12188
12189            let trigger_in_words =
12190                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12191
12192            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12193        });
12194    }
12195
12196    pub fn diff_clipboard_with_selection(
12197        &mut self,
12198        _: &DiffClipboardWithSelection,
12199        window: &mut Window,
12200        cx: &mut Context<Self>,
12201    ) {
12202        let selections = self.selections.all::<usize>(cx);
12203
12204        if selections.is_empty() {
12205            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12206            return;
12207        };
12208
12209        let clipboard_text = match cx.read_from_clipboard() {
12210            Some(item) => match item.entries().first() {
12211                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12212                _ => None,
12213            },
12214            None => None,
12215        };
12216
12217        let Some(clipboard_text) = clipboard_text else {
12218            log::warn!("Clipboard doesn't contain text.");
12219            return;
12220        };
12221
12222        window.dispatch_action(
12223            Box::new(DiffClipboardWithSelectionData {
12224                clipboard_text,
12225                editor: cx.entity(),
12226            }),
12227            cx,
12228        );
12229    }
12230
12231    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12233        if let Some(item) = cx.read_from_clipboard() {
12234            let entries = item.entries();
12235
12236            match entries.first() {
12237                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12238                // of all the pasted entries.
12239                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12240                    .do_paste(
12241                        clipboard_string.text(),
12242                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12243                        true,
12244                        window,
12245                        cx,
12246                    ),
12247                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12248            }
12249        }
12250    }
12251
12252    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12253        if self.read_only(cx) {
12254            return;
12255        }
12256
12257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12258
12259        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12260            if let Some((selections, _)) =
12261                self.selection_history.transaction(transaction_id).cloned()
12262            {
12263                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12264                    s.select_anchors(selections.to_vec());
12265                });
12266            } else {
12267                log::error!(
12268                    "No entry in selection_history found for undo. \
12269                     This may correspond to a bug where undo does not update the selection. \
12270                     If this is occurring, please add details to \
12271                     https://github.com/zed-industries/zed/issues/22692"
12272                );
12273            }
12274            self.request_autoscroll(Autoscroll::fit(), cx);
12275            self.unmark_text(window, cx);
12276            self.refresh_edit_prediction(true, false, window, cx);
12277            cx.emit(EditorEvent::Edited { transaction_id });
12278            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12279        }
12280    }
12281
12282    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12283        if self.read_only(cx) {
12284            return;
12285        }
12286
12287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12288
12289        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12290            if let Some((_, Some(selections))) =
12291                self.selection_history.transaction(transaction_id).cloned()
12292            {
12293                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12294                    s.select_anchors(selections.to_vec());
12295                });
12296            } else {
12297                log::error!(
12298                    "No entry in selection_history found for redo. \
12299                     This may correspond to a bug where undo does not update the selection. \
12300                     If this is occurring, please add details to \
12301                     https://github.com/zed-industries/zed/issues/22692"
12302                );
12303            }
12304            self.request_autoscroll(Autoscroll::fit(), cx);
12305            self.unmark_text(window, cx);
12306            self.refresh_edit_prediction(true, false, window, cx);
12307            cx.emit(EditorEvent::Edited { transaction_id });
12308        }
12309    }
12310
12311    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12312        self.buffer
12313            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12314    }
12315
12316    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12317        self.buffer
12318            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12319    }
12320
12321    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12323        self.change_selections(Default::default(), window, cx, |s| {
12324            s.move_with(|map, selection| {
12325                let cursor = if selection.is_empty() {
12326                    movement::left(map, selection.start)
12327                } else {
12328                    selection.start
12329                };
12330                selection.collapse_to(cursor, SelectionGoal::None);
12331            });
12332        })
12333    }
12334
12335    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12337        self.change_selections(Default::default(), window, cx, |s| {
12338            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12339        })
12340    }
12341
12342    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12344        self.change_selections(Default::default(), window, cx, |s| {
12345            s.move_with(|map, selection| {
12346                let cursor = if selection.is_empty() {
12347                    movement::right(map, selection.end)
12348                } else {
12349                    selection.end
12350                };
12351                selection.collapse_to(cursor, SelectionGoal::None)
12352            });
12353        })
12354    }
12355
12356    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12358        self.change_selections(Default::default(), window, cx, |s| {
12359            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12360        })
12361    }
12362
12363    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12364        if self.take_rename(true, window, cx).is_some() {
12365            return;
12366        }
12367
12368        if self.mode.is_single_line() {
12369            cx.propagate();
12370            return;
12371        }
12372
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12374
12375        let text_layout_details = &self.text_layout_details(window);
12376        let selection_count = self.selections.count();
12377        let first_selection = self.selections.first_anchor();
12378
12379        self.change_selections(Default::default(), window, cx, |s| {
12380            s.move_with(|map, selection| {
12381                if !selection.is_empty() {
12382                    selection.goal = SelectionGoal::None;
12383                }
12384                let (cursor, goal) = movement::up(
12385                    map,
12386                    selection.start,
12387                    selection.goal,
12388                    false,
12389                    text_layout_details,
12390                );
12391                selection.collapse_to(cursor, goal);
12392            });
12393        });
12394
12395        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12396        {
12397            cx.propagate();
12398        }
12399    }
12400
12401    pub fn move_up_by_lines(
12402        &mut self,
12403        action: &MoveUpByLines,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if self.take_rename(true, window, cx).is_some() {
12408            return;
12409        }
12410
12411        if self.mode.is_single_line() {
12412            cx.propagate();
12413            return;
12414        }
12415
12416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12417
12418        let text_layout_details = &self.text_layout_details(window);
12419
12420        self.change_selections(Default::default(), window, cx, |s| {
12421            s.move_with(|map, selection| {
12422                if !selection.is_empty() {
12423                    selection.goal = SelectionGoal::None;
12424                }
12425                let (cursor, goal) = movement::up_by_rows(
12426                    map,
12427                    selection.start,
12428                    action.lines,
12429                    selection.goal,
12430                    false,
12431                    text_layout_details,
12432                );
12433                selection.collapse_to(cursor, goal);
12434            });
12435        })
12436    }
12437
12438    pub fn move_down_by_lines(
12439        &mut self,
12440        action: &MoveDownByLines,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) {
12444        if self.take_rename(true, window, cx).is_some() {
12445            return;
12446        }
12447
12448        if self.mode.is_single_line() {
12449            cx.propagate();
12450            return;
12451        }
12452
12453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12454
12455        let text_layout_details = &self.text_layout_details(window);
12456
12457        self.change_selections(Default::default(), window, cx, |s| {
12458            s.move_with(|map, selection| {
12459                if !selection.is_empty() {
12460                    selection.goal = SelectionGoal::None;
12461                }
12462                let (cursor, goal) = movement::down_by_rows(
12463                    map,
12464                    selection.start,
12465                    action.lines,
12466                    selection.goal,
12467                    false,
12468                    text_layout_details,
12469                );
12470                selection.collapse_to(cursor, goal);
12471            });
12472        })
12473    }
12474
12475    pub fn select_down_by_lines(
12476        &mut self,
12477        action: &SelectDownByLines,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12482        let text_layout_details = &self.text_layout_details(window);
12483        self.change_selections(Default::default(), window, cx, |s| {
12484            s.move_heads_with(|map, head, goal| {
12485                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12486            })
12487        })
12488    }
12489
12490    pub fn select_up_by_lines(
12491        &mut self,
12492        action: &SelectUpByLines,
12493        window: &mut Window,
12494        cx: &mut Context<Self>,
12495    ) {
12496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12497        let text_layout_details = &self.text_layout_details(window);
12498        self.change_selections(Default::default(), window, cx, |s| {
12499            s.move_heads_with(|map, head, goal| {
12500                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12501            })
12502        })
12503    }
12504
12505    pub fn select_page_up(
12506        &mut self,
12507        _: &SelectPageUp,
12508        window: &mut Window,
12509        cx: &mut Context<Self>,
12510    ) {
12511        let Some(row_count) = self.visible_row_count() else {
12512            return;
12513        };
12514
12515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12516
12517        let text_layout_details = &self.text_layout_details(window);
12518
12519        self.change_selections(Default::default(), window, cx, |s| {
12520            s.move_heads_with(|map, head, goal| {
12521                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12522            })
12523        })
12524    }
12525
12526    pub fn move_page_up(
12527        &mut self,
12528        action: &MovePageUp,
12529        window: &mut Window,
12530        cx: &mut Context<Self>,
12531    ) {
12532        if self.take_rename(true, window, cx).is_some() {
12533            return;
12534        }
12535
12536        if self
12537            .context_menu
12538            .borrow_mut()
12539            .as_mut()
12540            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12541            .unwrap_or(false)
12542        {
12543            return;
12544        }
12545
12546        if matches!(self.mode, EditorMode::SingleLine) {
12547            cx.propagate();
12548            return;
12549        }
12550
12551        let Some(row_count) = self.visible_row_count() else {
12552            return;
12553        };
12554
12555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12556
12557        let effects = if action.center_cursor {
12558            SelectionEffects::scroll(Autoscroll::center())
12559        } else {
12560            SelectionEffects::default()
12561        };
12562
12563        let text_layout_details = &self.text_layout_details(window);
12564
12565        self.change_selections(effects, window, cx, |s| {
12566            s.move_with(|map, selection| {
12567                if !selection.is_empty() {
12568                    selection.goal = SelectionGoal::None;
12569                }
12570                let (cursor, goal) = movement::up_by_rows(
12571                    map,
12572                    selection.end,
12573                    row_count,
12574                    selection.goal,
12575                    false,
12576                    text_layout_details,
12577                );
12578                selection.collapse_to(cursor, goal);
12579            });
12580        });
12581    }
12582
12583    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12585        let text_layout_details = &self.text_layout_details(window);
12586        self.change_selections(Default::default(), window, cx, |s| {
12587            s.move_heads_with(|map, head, goal| {
12588                movement::up(map, head, goal, false, text_layout_details)
12589            })
12590        })
12591    }
12592
12593    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12594        self.take_rename(true, window, cx);
12595
12596        if self.mode.is_single_line() {
12597            cx.propagate();
12598            return;
12599        }
12600
12601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12602
12603        let text_layout_details = &self.text_layout_details(window);
12604        let selection_count = self.selections.count();
12605        let first_selection = self.selections.first_anchor();
12606
12607        self.change_selections(Default::default(), window, cx, |s| {
12608            s.move_with(|map, selection| {
12609                if !selection.is_empty() {
12610                    selection.goal = SelectionGoal::None;
12611                }
12612                let (cursor, goal) = movement::down(
12613                    map,
12614                    selection.end,
12615                    selection.goal,
12616                    false,
12617                    text_layout_details,
12618                );
12619                selection.collapse_to(cursor, goal);
12620            });
12621        });
12622
12623        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12624        {
12625            cx.propagate();
12626        }
12627    }
12628
12629    pub fn select_page_down(
12630        &mut self,
12631        _: &SelectPageDown,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        let Some(row_count) = self.visible_row_count() else {
12636            return;
12637        };
12638
12639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12640
12641        let text_layout_details = &self.text_layout_details(window);
12642
12643        self.change_selections(Default::default(), window, cx, |s| {
12644            s.move_heads_with(|map, head, goal| {
12645                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12646            })
12647        })
12648    }
12649
12650    pub fn move_page_down(
12651        &mut self,
12652        action: &MovePageDown,
12653        window: &mut Window,
12654        cx: &mut Context<Self>,
12655    ) {
12656        if self.take_rename(true, window, cx).is_some() {
12657            return;
12658        }
12659
12660        if self
12661            .context_menu
12662            .borrow_mut()
12663            .as_mut()
12664            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12665            .unwrap_or(false)
12666        {
12667            return;
12668        }
12669
12670        if matches!(self.mode, EditorMode::SingleLine) {
12671            cx.propagate();
12672            return;
12673        }
12674
12675        let Some(row_count) = self.visible_row_count() else {
12676            return;
12677        };
12678
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680
12681        let effects = if action.center_cursor {
12682            SelectionEffects::scroll(Autoscroll::center())
12683        } else {
12684            SelectionEffects::default()
12685        };
12686
12687        let text_layout_details = &self.text_layout_details(window);
12688        self.change_selections(effects, window, cx, |s| {
12689            s.move_with(|map, selection| {
12690                if !selection.is_empty() {
12691                    selection.goal = SelectionGoal::None;
12692                }
12693                let (cursor, goal) = movement::down_by_rows(
12694                    map,
12695                    selection.end,
12696                    row_count,
12697                    selection.goal,
12698                    false,
12699                    text_layout_details,
12700                );
12701                selection.collapse_to(cursor, goal);
12702            });
12703        });
12704    }
12705
12706    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12708        let text_layout_details = &self.text_layout_details(window);
12709        self.change_selections(Default::default(), window, cx, |s| {
12710            s.move_heads_with(|map, head, goal| {
12711                movement::down(map, head, goal, false, text_layout_details)
12712            })
12713        });
12714    }
12715
12716    pub fn context_menu_first(
12717        &mut self,
12718        _: &ContextMenuFirst,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12723            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12724        }
12725    }
12726
12727    pub fn context_menu_prev(
12728        &mut self,
12729        _: &ContextMenuPrevious,
12730        window: &mut Window,
12731        cx: &mut Context<Self>,
12732    ) {
12733        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12734            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12735        }
12736    }
12737
12738    pub fn context_menu_next(
12739        &mut self,
12740        _: &ContextMenuNext,
12741        window: &mut Window,
12742        cx: &mut Context<Self>,
12743    ) {
12744        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12745            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12746        }
12747    }
12748
12749    pub fn context_menu_last(
12750        &mut self,
12751        _: &ContextMenuLast,
12752        window: &mut Window,
12753        cx: &mut Context<Self>,
12754    ) {
12755        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12756            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12757        }
12758    }
12759
12760    pub fn signature_help_prev(
12761        &mut self,
12762        _: &SignatureHelpPrevious,
12763        _: &mut Window,
12764        cx: &mut Context<Self>,
12765    ) {
12766        if let Some(popover) = self.signature_help_state.popover_mut() {
12767            if popover.current_signature == 0 {
12768                popover.current_signature = popover.signatures.len() - 1;
12769            } else {
12770                popover.current_signature -= 1;
12771            }
12772            cx.notify();
12773        }
12774    }
12775
12776    pub fn signature_help_next(
12777        &mut self,
12778        _: &SignatureHelpNext,
12779        _: &mut Window,
12780        cx: &mut Context<Self>,
12781    ) {
12782        if let Some(popover) = self.signature_help_state.popover_mut() {
12783            if popover.current_signature + 1 == popover.signatures.len() {
12784                popover.current_signature = 0;
12785            } else {
12786                popover.current_signature += 1;
12787            }
12788            cx.notify();
12789        }
12790    }
12791
12792    pub fn move_to_previous_word_start(
12793        &mut self,
12794        _: &MoveToPreviousWordStart,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_cursors_with(|map, head, _| {
12801                (
12802                    movement::previous_word_start(map, head),
12803                    SelectionGoal::None,
12804                )
12805            });
12806        })
12807    }
12808
12809    pub fn move_to_previous_subword_start(
12810        &mut self,
12811        _: &MoveToPreviousSubwordStart,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12816        self.change_selections(Default::default(), window, cx, |s| {
12817            s.move_cursors_with(|map, head, _| {
12818                (
12819                    movement::previous_subword_start(map, head),
12820                    SelectionGoal::None,
12821                )
12822            });
12823        })
12824    }
12825
12826    pub fn select_to_previous_word_start(
12827        &mut self,
12828        _: &SelectToPreviousWordStart,
12829        window: &mut Window,
12830        cx: &mut Context<Self>,
12831    ) {
12832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12833        self.change_selections(Default::default(), window, cx, |s| {
12834            s.move_heads_with(|map, head, _| {
12835                (
12836                    movement::previous_word_start(map, head),
12837                    SelectionGoal::None,
12838                )
12839            });
12840        })
12841    }
12842
12843    pub fn select_to_previous_subword_start(
12844        &mut self,
12845        _: &SelectToPreviousSubwordStart,
12846        window: &mut Window,
12847        cx: &mut Context<Self>,
12848    ) {
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12850        self.change_selections(Default::default(), window, cx, |s| {
12851            s.move_heads_with(|map, head, _| {
12852                (
12853                    movement::previous_subword_start(map, head),
12854                    SelectionGoal::None,
12855                )
12856            });
12857        })
12858    }
12859
12860    pub fn delete_to_previous_word_start(
12861        &mut self,
12862        action: &DeleteToPreviousWordStart,
12863        window: &mut Window,
12864        cx: &mut Context<Self>,
12865    ) {
12866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12867        self.transact(window, cx, |this, window, cx| {
12868            this.select_autoclose_pair(window, cx);
12869            this.change_selections(Default::default(), window, cx, |s| {
12870                s.move_with(|map, selection| {
12871                    if selection.is_empty() {
12872                        let cursor = if action.ignore_newlines {
12873                            movement::previous_word_start(map, selection.head())
12874                        } else {
12875                            movement::previous_word_start_or_newline(map, selection.head())
12876                        };
12877                        selection.set_head(cursor, SelectionGoal::None);
12878                    }
12879                });
12880            });
12881            this.insert("", window, cx);
12882        });
12883    }
12884
12885    pub fn delete_to_previous_subword_start(
12886        &mut self,
12887        _: &DeleteToPreviousSubwordStart,
12888        window: &mut Window,
12889        cx: &mut Context<Self>,
12890    ) {
12891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12892        self.transact(window, cx, |this, window, cx| {
12893            this.select_autoclose_pair(window, cx);
12894            this.change_selections(Default::default(), window, cx, |s| {
12895                s.move_with(|map, selection| {
12896                    if selection.is_empty() {
12897                        let cursor = movement::previous_subword_start(map, selection.head());
12898                        selection.set_head(cursor, SelectionGoal::None);
12899                    }
12900                });
12901            });
12902            this.insert("", window, cx);
12903        });
12904    }
12905
12906    pub fn move_to_next_word_end(
12907        &mut self,
12908        _: &MoveToNextWordEnd,
12909        window: &mut Window,
12910        cx: &mut Context<Self>,
12911    ) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_cursors_with(|map, head, _| {
12915                (movement::next_word_end(map, head), SelectionGoal::None)
12916            });
12917        })
12918    }
12919
12920    pub fn move_to_next_subword_end(
12921        &mut self,
12922        _: &MoveToNextSubwordEnd,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_cursors_with(|map, head, _| {
12929                (movement::next_subword_end(map, head), SelectionGoal::None)
12930            });
12931        })
12932    }
12933
12934    pub fn select_to_next_word_end(
12935        &mut self,
12936        _: &SelectToNextWordEnd,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941        self.change_selections(Default::default(), window, cx, |s| {
12942            s.move_heads_with(|map, head, _| {
12943                (movement::next_word_end(map, head), SelectionGoal::None)
12944            });
12945        })
12946    }
12947
12948    pub fn select_to_next_subword_end(
12949        &mut self,
12950        _: &SelectToNextSubwordEnd,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955        self.change_selections(Default::default(), window, cx, |s| {
12956            s.move_heads_with(|map, head, _| {
12957                (movement::next_subword_end(map, head), SelectionGoal::None)
12958            });
12959        })
12960    }
12961
12962    pub fn delete_to_next_word_end(
12963        &mut self,
12964        action: &DeleteToNextWordEnd,
12965        window: &mut Window,
12966        cx: &mut Context<Self>,
12967    ) {
12968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12969        self.transact(window, cx, |this, window, cx| {
12970            this.change_selections(Default::default(), window, cx, |s| {
12971                s.move_with(|map, selection| {
12972                    if selection.is_empty() {
12973                        let cursor = if action.ignore_newlines {
12974                            movement::next_word_end(map, selection.head())
12975                        } else {
12976                            movement::next_word_end_or_newline(map, selection.head())
12977                        };
12978                        selection.set_head(cursor, SelectionGoal::None);
12979                    }
12980                });
12981            });
12982            this.insert("", window, cx);
12983        });
12984    }
12985
12986    pub fn delete_to_next_subword_end(
12987        &mut self,
12988        _: &DeleteToNextSubwordEnd,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12993        self.transact(window, cx, |this, window, cx| {
12994            this.change_selections(Default::default(), window, cx, |s| {
12995                s.move_with(|map, selection| {
12996                    if selection.is_empty() {
12997                        let cursor = movement::next_subword_end(map, selection.head());
12998                        selection.set_head(cursor, SelectionGoal::None);
12999                    }
13000                });
13001            });
13002            this.insert("", window, cx);
13003        });
13004    }
13005
13006    pub fn move_to_beginning_of_line(
13007        &mut self,
13008        action: &MoveToBeginningOfLine,
13009        window: &mut Window,
13010        cx: &mut Context<Self>,
13011    ) {
13012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13013        self.change_selections(Default::default(), window, cx, |s| {
13014            s.move_cursors_with(|map, head, _| {
13015                (
13016                    movement::indented_line_beginning(
13017                        map,
13018                        head,
13019                        action.stop_at_soft_wraps,
13020                        action.stop_at_indent,
13021                    ),
13022                    SelectionGoal::None,
13023                )
13024            });
13025        })
13026    }
13027
13028    pub fn select_to_beginning_of_line(
13029        &mut self,
13030        action: &SelectToBeginningOfLine,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) {
13034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13035        self.change_selections(Default::default(), window, cx, |s| {
13036            s.move_heads_with(|map, head, _| {
13037                (
13038                    movement::indented_line_beginning(
13039                        map,
13040                        head,
13041                        action.stop_at_soft_wraps,
13042                        action.stop_at_indent,
13043                    ),
13044                    SelectionGoal::None,
13045                )
13046            });
13047        });
13048    }
13049
13050    pub fn delete_to_beginning_of_line(
13051        &mut self,
13052        action: &DeleteToBeginningOfLine,
13053        window: &mut Window,
13054        cx: &mut Context<Self>,
13055    ) {
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13057        self.transact(window, cx, |this, window, cx| {
13058            this.change_selections(Default::default(), window, cx, |s| {
13059                s.move_with(|_, selection| {
13060                    selection.reversed = true;
13061                });
13062            });
13063
13064            this.select_to_beginning_of_line(
13065                &SelectToBeginningOfLine {
13066                    stop_at_soft_wraps: false,
13067                    stop_at_indent: action.stop_at_indent,
13068                },
13069                window,
13070                cx,
13071            );
13072            this.backspace(&Backspace, window, cx);
13073        });
13074    }
13075
13076    pub fn move_to_end_of_line(
13077        &mut self,
13078        action: &MoveToEndOfLine,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) {
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_cursors_with(|map, head, _| {
13085                (
13086                    movement::line_end(map, head, action.stop_at_soft_wraps),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn select_to_end_of_line(
13094        &mut self,
13095        action: &SelectToEndOfLine,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_heads_with(|map, head, _| {
13102                (
13103                    movement::line_end(map, head, action.stop_at_soft_wraps),
13104                    SelectionGoal::None,
13105                )
13106            });
13107        })
13108    }
13109
13110    pub fn delete_to_end_of_line(
13111        &mut self,
13112        _: &DeleteToEndOfLine,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13117        self.transact(window, cx, |this, window, cx| {
13118            this.select_to_end_of_line(
13119                &SelectToEndOfLine {
13120                    stop_at_soft_wraps: false,
13121                },
13122                window,
13123                cx,
13124            );
13125            this.delete(&Delete, window, cx);
13126        });
13127    }
13128
13129    pub fn cut_to_end_of_line(
13130        &mut self,
13131        _: &CutToEndOfLine,
13132        window: &mut Window,
13133        cx: &mut Context<Self>,
13134    ) {
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13136        self.transact(window, cx, |this, window, cx| {
13137            this.select_to_end_of_line(
13138                &SelectToEndOfLine {
13139                    stop_at_soft_wraps: false,
13140                },
13141                window,
13142                cx,
13143            );
13144            this.cut(&Cut, window, cx);
13145        });
13146    }
13147
13148    pub fn move_to_start_of_paragraph(
13149        &mut self,
13150        _: &MoveToStartOfParagraph,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        if matches!(self.mode, EditorMode::SingleLine) {
13155            cx.propagate();
13156            return;
13157        }
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159        self.change_selections(Default::default(), window, cx, |s| {
13160            s.move_with(|map, selection| {
13161                selection.collapse_to(
13162                    movement::start_of_paragraph(map, selection.head(), 1),
13163                    SelectionGoal::None,
13164                )
13165            });
13166        })
13167    }
13168
13169    pub fn move_to_end_of_paragraph(
13170        &mut self,
13171        _: &MoveToEndOfParagraph,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        if matches!(self.mode, EditorMode::SingleLine) {
13176            cx.propagate();
13177            return;
13178        }
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_with(|map, selection| {
13182                selection.collapse_to(
13183                    movement::end_of_paragraph(map, selection.head(), 1),
13184                    SelectionGoal::None,
13185                )
13186            });
13187        })
13188    }
13189
13190    pub fn select_to_start_of_paragraph(
13191        &mut self,
13192        _: &SelectToStartOfParagraph,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        if matches!(self.mode, EditorMode::SingleLine) {
13197            cx.propagate();
13198            return;
13199        }
13200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13201        self.change_selections(Default::default(), window, cx, |s| {
13202            s.move_heads_with(|map, head, _| {
13203                (
13204                    movement::start_of_paragraph(map, head, 1),
13205                    SelectionGoal::None,
13206                )
13207            });
13208        })
13209    }
13210
13211    pub fn select_to_end_of_paragraph(
13212        &mut self,
13213        _: &SelectToEndOfParagraph,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        if matches!(self.mode, EditorMode::SingleLine) {
13218            cx.propagate();
13219            return;
13220        }
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222        self.change_selections(Default::default(), window, cx, |s| {
13223            s.move_heads_with(|map, head, _| {
13224                (
13225                    movement::end_of_paragraph(map, head, 1),
13226                    SelectionGoal::None,
13227                )
13228            });
13229        })
13230    }
13231
13232    pub fn move_to_start_of_excerpt(
13233        &mut self,
13234        _: &MoveToStartOfExcerpt,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        if matches!(self.mode, EditorMode::SingleLine) {
13239            cx.propagate();
13240            return;
13241        }
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        self.change_selections(Default::default(), window, cx, |s| {
13244            s.move_with(|map, selection| {
13245                selection.collapse_to(
13246                    movement::start_of_excerpt(
13247                        map,
13248                        selection.head(),
13249                        workspace::searchable::Direction::Prev,
13250                    ),
13251                    SelectionGoal::None,
13252                )
13253            });
13254        })
13255    }
13256
13257    pub fn move_to_start_of_next_excerpt(
13258        &mut self,
13259        _: &MoveToStartOfNextExcerpt,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        if matches!(self.mode, EditorMode::SingleLine) {
13264            cx.propagate();
13265            return;
13266        }
13267
13268        self.change_selections(Default::default(), window, cx, |s| {
13269            s.move_with(|map, selection| {
13270                selection.collapse_to(
13271                    movement::start_of_excerpt(
13272                        map,
13273                        selection.head(),
13274                        workspace::searchable::Direction::Next,
13275                    ),
13276                    SelectionGoal::None,
13277                )
13278            });
13279        })
13280    }
13281
13282    pub fn move_to_end_of_excerpt(
13283        &mut self,
13284        _: &MoveToEndOfExcerpt,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if matches!(self.mode, EditorMode::SingleLine) {
13289            cx.propagate();
13290            return;
13291        }
13292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.move_with(|map, selection| {
13295                selection.collapse_to(
13296                    movement::end_of_excerpt(
13297                        map,
13298                        selection.head(),
13299                        workspace::searchable::Direction::Next,
13300                    ),
13301                    SelectionGoal::None,
13302                )
13303            });
13304        })
13305    }
13306
13307    pub fn move_to_end_of_previous_excerpt(
13308        &mut self,
13309        _: &MoveToEndOfPreviousExcerpt,
13310        window: &mut Window,
13311        cx: &mut Context<Self>,
13312    ) {
13313        if matches!(self.mode, EditorMode::SingleLine) {
13314            cx.propagate();
13315            return;
13316        }
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13318        self.change_selections(Default::default(), window, cx, |s| {
13319            s.move_with(|map, selection| {
13320                selection.collapse_to(
13321                    movement::end_of_excerpt(
13322                        map,
13323                        selection.head(),
13324                        workspace::searchable::Direction::Prev,
13325                    ),
13326                    SelectionGoal::None,
13327                )
13328            });
13329        })
13330    }
13331
13332    pub fn select_to_start_of_excerpt(
13333        &mut self,
13334        _: &SelectToStartOfExcerpt,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        if matches!(self.mode, EditorMode::SingleLine) {
13339            cx.propagate();
13340            return;
13341        }
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.move_heads_with(|map, head, _| {
13345                (
13346                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13347                    SelectionGoal::None,
13348                )
13349            });
13350        })
13351    }
13352
13353    pub fn select_to_start_of_next_excerpt(
13354        &mut self,
13355        _: &SelectToStartOfNextExcerpt,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        if matches!(self.mode, EditorMode::SingleLine) {
13360            cx.propagate();
13361            return;
13362        }
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_heads_with(|map, head, _| {
13366                (
13367                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13368                    SelectionGoal::None,
13369                )
13370            });
13371        })
13372    }
13373
13374    pub fn select_to_end_of_excerpt(
13375        &mut self,
13376        _: &SelectToEndOfExcerpt,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        if matches!(self.mode, EditorMode::SingleLine) {
13381            cx.propagate();
13382            return;
13383        }
13384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13385        self.change_selections(Default::default(), window, cx, |s| {
13386            s.move_heads_with(|map, head, _| {
13387                (
13388                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13389                    SelectionGoal::None,
13390                )
13391            });
13392        })
13393    }
13394
13395    pub fn select_to_end_of_previous_excerpt(
13396        &mut self,
13397        _: &SelectToEndOfPreviousExcerpt,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        if matches!(self.mode, EditorMode::SingleLine) {
13402            cx.propagate();
13403            return;
13404        }
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_heads_with(|map, head, _| {
13408                (
13409                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn move_to_beginning(
13417        &mut self,
13418        _: &MoveToBeginning,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        if matches!(self.mode, EditorMode::SingleLine) {
13423            cx.propagate();
13424            return;
13425        }
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        self.change_selections(Default::default(), window, cx, |s| {
13428            s.select_ranges(vec![0..0]);
13429        });
13430    }
13431
13432    pub fn select_to_beginning(
13433        &mut self,
13434        _: &SelectToBeginning,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        let mut selection = self.selections.last::<Point>(cx);
13439        selection.set_head(Point::zero(), SelectionGoal::None);
13440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.select(vec![selection]);
13443        });
13444    }
13445
13446    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13447        if matches!(self.mode, EditorMode::SingleLine) {
13448            cx.propagate();
13449            return;
13450        }
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        let cursor = self.buffer.read(cx).read(cx).len();
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.select_ranges(vec![cursor..cursor])
13455        });
13456    }
13457
13458    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13459        self.nav_history = nav_history;
13460    }
13461
13462    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13463        self.nav_history.as_ref()
13464    }
13465
13466    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13467        self.push_to_nav_history(
13468            self.selections.newest_anchor().head(),
13469            None,
13470            false,
13471            true,
13472            cx,
13473        );
13474    }
13475
13476    fn push_to_nav_history(
13477        &mut self,
13478        cursor_anchor: Anchor,
13479        new_position: Option<Point>,
13480        is_deactivate: bool,
13481        always: bool,
13482        cx: &mut Context<Self>,
13483    ) {
13484        if let Some(nav_history) = self.nav_history.as_mut() {
13485            let buffer = self.buffer.read(cx).read(cx);
13486            let cursor_position = cursor_anchor.to_point(&buffer);
13487            let scroll_state = self.scroll_manager.anchor();
13488            let scroll_top_row = scroll_state.top_row(&buffer);
13489            drop(buffer);
13490
13491            if let Some(new_position) = new_position {
13492                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13493                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13494                    return;
13495                }
13496            }
13497
13498            nav_history.push(
13499                Some(NavigationData {
13500                    cursor_anchor,
13501                    cursor_position,
13502                    scroll_anchor: scroll_state,
13503                    scroll_top_row,
13504                }),
13505                cx,
13506            );
13507            cx.emit(EditorEvent::PushedToNavHistory {
13508                anchor: cursor_anchor,
13509                is_deactivate,
13510            })
13511        }
13512    }
13513
13514    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13516        let buffer = self.buffer.read(cx).snapshot(cx);
13517        let mut selection = self.selections.first::<usize>(cx);
13518        selection.set_head(buffer.len(), SelectionGoal::None);
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.select(vec![selection]);
13521        });
13522    }
13523
13524    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13526        let end = self.buffer.read(cx).read(cx).len();
13527        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13528            s.select_ranges(vec![0..end]);
13529        });
13530    }
13531
13532    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13533        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13535        let mut selections = self.selections.all::<Point>(cx);
13536        let max_point = display_map.buffer_snapshot.max_point();
13537        for selection in &mut selections {
13538            let rows = selection.spanned_rows(true, &display_map);
13539            selection.start = Point::new(rows.start.0, 0);
13540            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13541            selection.reversed = false;
13542        }
13543        self.change_selections(Default::default(), window, cx, |s| {
13544            s.select(selections);
13545        });
13546    }
13547
13548    pub fn split_selection_into_lines(
13549        &mut self,
13550        action: &SplitSelectionIntoLines,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) {
13554        let selections = self
13555            .selections
13556            .all::<Point>(cx)
13557            .into_iter()
13558            .map(|selection| selection.start..selection.end)
13559            .collect::<Vec<_>>();
13560        self.unfold_ranges(&selections, true, true, cx);
13561
13562        let mut new_selection_ranges = Vec::new();
13563        {
13564            let buffer = self.buffer.read(cx).read(cx);
13565            for selection in selections {
13566                for row in selection.start.row..selection.end.row {
13567                    let line_start = Point::new(row, 0);
13568                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13569
13570                    if action.keep_selections {
13571                        // Keep the selection range for each line
13572                        let selection_start = if row == selection.start.row {
13573                            selection.start
13574                        } else {
13575                            line_start
13576                        };
13577                        new_selection_ranges.push(selection_start..line_end);
13578                    } else {
13579                        // Collapse to cursor at end of line
13580                        new_selection_ranges.push(line_end..line_end);
13581                    }
13582                }
13583
13584                let is_multiline_selection = selection.start.row != selection.end.row;
13585                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13586                // so this action feels more ergonomic when paired with other selection operations
13587                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13588                if !should_skip_last {
13589                    if action.keep_selections {
13590                        if is_multiline_selection {
13591                            let line_start = Point::new(selection.end.row, 0);
13592                            new_selection_ranges.push(line_start..selection.end);
13593                        } else {
13594                            new_selection_ranges.push(selection.start..selection.end);
13595                        }
13596                    } else {
13597                        new_selection_ranges.push(selection.end..selection.end);
13598                    }
13599                }
13600            }
13601        }
13602        self.change_selections(Default::default(), window, cx, |s| {
13603            s.select_ranges(new_selection_ranges);
13604        });
13605    }
13606
13607    pub fn add_selection_above(
13608        &mut self,
13609        _: &AddSelectionAbove,
13610        window: &mut Window,
13611        cx: &mut Context<Self>,
13612    ) {
13613        self.add_selection(true, window, cx);
13614    }
13615
13616    pub fn add_selection_below(
13617        &mut self,
13618        _: &AddSelectionBelow,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        self.add_selection(false, window, cx);
13623    }
13624
13625    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627
13628        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13629        let all_selections = self.selections.all::<Point>(cx);
13630        let text_layout_details = self.text_layout_details(window);
13631
13632        let (mut columnar_selections, new_selections_to_columnarize) = {
13633            if let Some(state) = self.add_selections_state.as_ref() {
13634                let columnar_selection_ids: HashSet<_> = state
13635                    .groups
13636                    .iter()
13637                    .flat_map(|group| group.stack.iter())
13638                    .copied()
13639                    .collect();
13640
13641                all_selections
13642                    .into_iter()
13643                    .partition(|s| columnar_selection_ids.contains(&s.id))
13644            } else {
13645                (Vec::new(), all_selections)
13646            }
13647        };
13648
13649        let mut state = self
13650            .add_selections_state
13651            .take()
13652            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13653
13654        for selection in new_selections_to_columnarize {
13655            let range = selection.display_range(&display_map).sorted();
13656            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13657            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13658            let positions = start_x.min(end_x)..start_x.max(end_x);
13659            let mut stack = Vec::new();
13660            for row in range.start.row().0..=range.end.row().0 {
13661                if let Some(selection) = self.selections.build_columnar_selection(
13662                    &display_map,
13663                    DisplayRow(row),
13664                    &positions,
13665                    selection.reversed,
13666                    &text_layout_details,
13667                ) {
13668                    stack.push(selection.id);
13669                    columnar_selections.push(selection);
13670                }
13671            }
13672            if !stack.is_empty() {
13673                if above {
13674                    stack.reverse();
13675                }
13676                state.groups.push(AddSelectionsGroup { above, stack });
13677            }
13678        }
13679
13680        let mut final_selections = Vec::new();
13681        let end_row = if above {
13682            DisplayRow(0)
13683        } else {
13684            display_map.max_point().row()
13685        };
13686
13687        let mut last_added_item_per_group = HashMap::default();
13688        for group in state.groups.iter_mut() {
13689            if let Some(last_id) = group.stack.last() {
13690                last_added_item_per_group.insert(*last_id, group);
13691            }
13692        }
13693
13694        for selection in columnar_selections {
13695            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13696                if above == group.above {
13697                    let range = selection.display_range(&display_map).sorted();
13698                    debug_assert_eq!(range.start.row(), range.end.row());
13699                    let mut row = range.start.row();
13700                    let positions =
13701                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13702                            px(start)..px(end)
13703                        } else {
13704                            let start_x =
13705                                display_map.x_for_display_point(range.start, &text_layout_details);
13706                            let end_x =
13707                                display_map.x_for_display_point(range.end, &text_layout_details);
13708                            start_x.min(end_x)..start_x.max(end_x)
13709                        };
13710
13711                    let mut maybe_new_selection = None;
13712                    while row != end_row {
13713                        if above {
13714                            row.0 -= 1;
13715                        } else {
13716                            row.0 += 1;
13717                        }
13718                        if let Some(new_selection) = self.selections.build_columnar_selection(
13719                            &display_map,
13720                            row,
13721                            &positions,
13722                            selection.reversed,
13723                            &text_layout_details,
13724                        ) {
13725                            maybe_new_selection = Some(new_selection);
13726                            break;
13727                        }
13728                    }
13729
13730                    if let Some(new_selection) = maybe_new_selection {
13731                        group.stack.push(new_selection.id);
13732                        if above {
13733                            final_selections.push(new_selection);
13734                            final_selections.push(selection);
13735                        } else {
13736                            final_selections.push(selection);
13737                            final_selections.push(new_selection);
13738                        }
13739                    } else {
13740                        final_selections.push(selection);
13741                    }
13742                } else {
13743                    group.stack.pop();
13744                }
13745            } else {
13746                final_selections.push(selection);
13747            }
13748        }
13749
13750        self.change_selections(Default::default(), window, cx, |s| {
13751            s.select(final_selections);
13752        });
13753
13754        let final_selection_ids: HashSet<_> = self
13755            .selections
13756            .all::<Point>(cx)
13757            .iter()
13758            .map(|s| s.id)
13759            .collect();
13760        state.groups.retain_mut(|group| {
13761            // selections might get merged above so we remove invalid items from stacks
13762            group.stack.retain(|id| final_selection_ids.contains(id));
13763
13764            // single selection in stack can be treated as initial state
13765            group.stack.len() > 1
13766        });
13767
13768        if !state.groups.is_empty() {
13769            self.add_selections_state = Some(state);
13770        }
13771    }
13772
13773    fn select_match_ranges(
13774        &mut self,
13775        range: Range<usize>,
13776        reversed: bool,
13777        replace_newest: bool,
13778        auto_scroll: Option<Autoscroll>,
13779        window: &mut Window,
13780        cx: &mut Context<Editor>,
13781    ) {
13782        self.unfold_ranges(
13783            std::slice::from_ref(&range),
13784            false,
13785            auto_scroll.is_some(),
13786            cx,
13787        );
13788        let effects = if let Some(scroll) = auto_scroll {
13789            SelectionEffects::scroll(scroll)
13790        } else {
13791            SelectionEffects::no_scroll()
13792        };
13793        self.change_selections(effects, window, cx, |s| {
13794            if replace_newest {
13795                s.delete(s.newest_anchor().id);
13796            }
13797            if reversed {
13798                s.insert_range(range.end..range.start);
13799            } else {
13800                s.insert_range(range);
13801            }
13802        });
13803    }
13804
13805    pub fn select_next_match_internal(
13806        &mut self,
13807        display_map: &DisplaySnapshot,
13808        replace_newest: bool,
13809        autoscroll: Option<Autoscroll>,
13810        window: &mut Window,
13811        cx: &mut Context<Self>,
13812    ) -> Result<()> {
13813        let buffer = &display_map.buffer_snapshot;
13814        let mut selections = self.selections.all::<usize>(cx);
13815        if let Some(mut select_next_state) = self.select_next_state.take() {
13816            let query = &select_next_state.query;
13817            if !select_next_state.done {
13818                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13819                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13820                let mut next_selected_range = None;
13821
13822                let bytes_after_last_selection =
13823                    buffer.bytes_in_range(last_selection.end..buffer.len());
13824                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13825                let query_matches = query
13826                    .stream_find_iter(bytes_after_last_selection)
13827                    .map(|result| (last_selection.end, result))
13828                    .chain(
13829                        query
13830                            .stream_find_iter(bytes_before_first_selection)
13831                            .map(|result| (0, result)),
13832                    );
13833
13834                for (start_offset, query_match) in query_matches {
13835                    let query_match = query_match.unwrap(); // can only fail due to I/O
13836                    let offset_range =
13837                        start_offset + query_match.start()..start_offset + query_match.end();
13838
13839                    if !select_next_state.wordwise
13840                        || (!buffer.is_inside_word(offset_range.start, false)
13841                            && !buffer.is_inside_word(offset_range.end, false))
13842                    {
13843                        // TODO: This is n^2, because we might check all the selections
13844                        if !selections
13845                            .iter()
13846                            .any(|selection| selection.range().overlaps(&offset_range))
13847                        {
13848                            next_selected_range = Some(offset_range);
13849                            break;
13850                        }
13851                    }
13852                }
13853
13854                if let Some(next_selected_range) = next_selected_range {
13855                    self.select_match_ranges(
13856                        next_selected_range,
13857                        last_selection.reversed,
13858                        replace_newest,
13859                        autoscroll,
13860                        window,
13861                        cx,
13862                    );
13863                } else {
13864                    select_next_state.done = true;
13865                }
13866            }
13867
13868            self.select_next_state = Some(select_next_state);
13869        } else {
13870            let mut only_carets = true;
13871            let mut same_text_selected = true;
13872            let mut selected_text = None;
13873
13874            let mut selections_iter = selections.iter().peekable();
13875            while let Some(selection) = selections_iter.next() {
13876                if selection.start != selection.end {
13877                    only_carets = false;
13878                }
13879
13880                if same_text_selected {
13881                    if selected_text.is_none() {
13882                        selected_text =
13883                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13884                    }
13885
13886                    if let Some(next_selection) = selections_iter.peek() {
13887                        if next_selection.range().len() == selection.range().len() {
13888                            let next_selected_text = buffer
13889                                .text_for_range(next_selection.range())
13890                                .collect::<String>();
13891                            if Some(next_selected_text) != selected_text {
13892                                same_text_selected = false;
13893                                selected_text = None;
13894                            }
13895                        } else {
13896                            same_text_selected = false;
13897                            selected_text = None;
13898                        }
13899                    }
13900                }
13901            }
13902
13903            if only_carets {
13904                for selection in &mut selections {
13905                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13906                    selection.start = word_range.start;
13907                    selection.end = word_range.end;
13908                    selection.goal = SelectionGoal::None;
13909                    selection.reversed = false;
13910                    self.select_match_ranges(
13911                        selection.start..selection.end,
13912                        selection.reversed,
13913                        replace_newest,
13914                        autoscroll,
13915                        window,
13916                        cx,
13917                    );
13918                }
13919
13920                if selections.len() == 1 {
13921                    let selection = selections
13922                        .last()
13923                        .expect("ensured that there's only one selection");
13924                    let query = buffer
13925                        .text_for_range(selection.start..selection.end)
13926                        .collect::<String>();
13927                    let is_empty = query.is_empty();
13928                    let select_state = SelectNextState {
13929                        query: AhoCorasick::new(&[query])?,
13930                        wordwise: true,
13931                        done: is_empty,
13932                    };
13933                    self.select_next_state = Some(select_state);
13934                } else {
13935                    self.select_next_state = None;
13936                }
13937            } else if let Some(selected_text) = selected_text {
13938                self.select_next_state = Some(SelectNextState {
13939                    query: AhoCorasick::new(&[selected_text])?,
13940                    wordwise: false,
13941                    done: false,
13942                });
13943                self.select_next_match_internal(
13944                    display_map,
13945                    replace_newest,
13946                    autoscroll,
13947                    window,
13948                    cx,
13949                )?;
13950            }
13951        }
13952        Ok(())
13953    }
13954
13955    pub fn select_all_matches(
13956        &mut self,
13957        _action: &SelectAllMatches,
13958        window: &mut Window,
13959        cx: &mut Context<Self>,
13960    ) -> Result<()> {
13961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13962
13963        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13964
13965        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13966        let Some(select_next_state) = self.select_next_state.as_mut() else {
13967            return Ok(());
13968        };
13969        if select_next_state.done {
13970            return Ok(());
13971        }
13972
13973        let mut new_selections = Vec::new();
13974
13975        let reversed = self.selections.oldest::<usize>(cx).reversed;
13976        let buffer = &display_map.buffer_snapshot;
13977        let query_matches = select_next_state
13978            .query
13979            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13980
13981        for query_match in query_matches.into_iter() {
13982            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13983            let offset_range = if reversed {
13984                query_match.end()..query_match.start()
13985            } else {
13986                query_match.start()..query_match.end()
13987            };
13988
13989            if !select_next_state.wordwise
13990                || (!buffer.is_inside_word(offset_range.start, false)
13991                    && !buffer.is_inside_word(offset_range.end, false))
13992            {
13993                new_selections.push(offset_range.start..offset_range.end);
13994            }
13995        }
13996
13997        select_next_state.done = true;
13998
13999        if new_selections.is_empty() {
14000            log::error!("bug: new_selections is empty in select_all_matches");
14001            return Ok(());
14002        }
14003
14004        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14005        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14006            selections.select_ranges(new_selections)
14007        });
14008
14009        Ok(())
14010    }
14011
14012    pub fn select_next(
14013        &mut self,
14014        action: &SelectNext,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) -> Result<()> {
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14020        self.select_next_match_internal(
14021            &display_map,
14022            action.replace_newest,
14023            Some(Autoscroll::newest()),
14024            window,
14025            cx,
14026        )?;
14027        Ok(())
14028    }
14029
14030    pub fn select_previous(
14031        &mut self,
14032        action: &SelectPrevious,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) -> Result<()> {
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14038        let buffer = &display_map.buffer_snapshot;
14039        let mut selections = self.selections.all::<usize>(cx);
14040        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14041            let query = &select_prev_state.query;
14042            if !select_prev_state.done {
14043                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14044                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14045                let mut next_selected_range = None;
14046                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14047                let bytes_before_last_selection =
14048                    buffer.reversed_bytes_in_range(0..last_selection.start);
14049                let bytes_after_first_selection =
14050                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14051                let query_matches = query
14052                    .stream_find_iter(bytes_before_last_selection)
14053                    .map(|result| (last_selection.start, result))
14054                    .chain(
14055                        query
14056                            .stream_find_iter(bytes_after_first_selection)
14057                            .map(|result| (buffer.len(), result)),
14058                    );
14059                for (end_offset, query_match) in query_matches {
14060                    let query_match = query_match.unwrap(); // can only fail due to I/O
14061                    let offset_range =
14062                        end_offset - query_match.end()..end_offset - query_match.start();
14063
14064                    if !select_prev_state.wordwise
14065                        || (!buffer.is_inside_word(offset_range.start, false)
14066                            && !buffer.is_inside_word(offset_range.end, false))
14067                    {
14068                        next_selected_range = Some(offset_range);
14069                        break;
14070                    }
14071                }
14072
14073                if let Some(next_selected_range) = next_selected_range {
14074                    self.select_match_ranges(
14075                        next_selected_range,
14076                        last_selection.reversed,
14077                        action.replace_newest,
14078                        Some(Autoscroll::newest()),
14079                        window,
14080                        cx,
14081                    );
14082                } else {
14083                    select_prev_state.done = true;
14084                }
14085            }
14086
14087            self.select_prev_state = Some(select_prev_state);
14088        } else {
14089            let mut only_carets = true;
14090            let mut same_text_selected = true;
14091            let mut selected_text = None;
14092
14093            let mut selections_iter = selections.iter().peekable();
14094            while let Some(selection) = selections_iter.next() {
14095                if selection.start != selection.end {
14096                    only_carets = false;
14097                }
14098
14099                if same_text_selected {
14100                    if selected_text.is_none() {
14101                        selected_text =
14102                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14103                    }
14104
14105                    if let Some(next_selection) = selections_iter.peek() {
14106                        if next_selection.range().len() == selection.range().len() {
14107                            let next_selected_text = buffer
14108                                .text_for_range(next_selection.range())
14109                                .collect::<String>();
14110                            if Some(next_selected_text) != selected_text {
14111                                same_text_selected = false;
14112                                selected_text = None;
14113                            }
14114                        } else {
14115                            same_text_selected = false;
14116                            selected_text = None;
14117                        }
14118                    }
14119                }
14120            }
14121
14122            if only_carets {
14123                for selection in &mut selections {
14124                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14125                    selection.start = word_range.start;
14126                    selection.end = word_range.end;
14127                    selection.goal = SelectionGoal::None;
14128                    selection.reversed = false;
14129                    self.select_match_ranges(
14130                        selection.start..selection.end,
14131                        selection.reversed,
14132                        action.replace_newest,
14133                        Some(Autoscroll::newest()),
14134                        window,
14135                        cx,
14136                    );
14137                }
14138                if selections.len() == 1 {
14139                    let selection = selections
14140                        .last()
14141                        .expect("ensured that there's only one selection");
14142                    let query = buffer
14143                        .text_for_range(selection.start..selection.end)
14144                        .collect::<String>();
14145                    let is_empty = query.is_empty();
14146                    let select_state = SelectNextState {
14147                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14148                        wordwise: true,
14149                        done: is_empty,
14150                    };
14151                    self.select_prev_state = Some(select_state);
14152                } else {
14153                    self.select_prev_state = None;
14154                }
14155            } else if let Some(selected_text) = selected_text {
14156                self.select_prev_state = Some(SelectNextState {
14157                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14158                    wordwise: false,
14159                    done: false,
14160                });
14161                self.select_previous(action, window, cx)?;
14162            }
14163        }
14164        Ok(())
14165    }
14166
14167    pub fn find_next_match(
14168        &mut self,
14169        _: &FindNextMatch,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) -> Result<()> {
14173        let selections = self.selections.disjoint_anchors();
14174        match selections.first() {
14175            Some(first) if selections.len() >= 2 => {
14176                self.change_selections(Default::default(), window, cx, |s| {
14177                    s.select_ranges([first.range()]);
14178                });
14179            }
14180            _ => self.select_next(
14181                &SelectNext {
14182                    replace_newest: true,
14183                },
14184                window,
14185                cx,
14186            )?,
14187        }
14188        Ok(())
14189    }
14190
14191    pub fn find_previous_match(
14192        &mut self,
14193        _: &FindPreviousMatch,
14194        window: &mut Window,
14195        cx: &mut Context<Self>,
14196    ) -> Result<()> {
14197        let selections = self.selections.disjoint_anchors();
14198        match selections.last() {
14199            Some(last) if selections.len() >= 2 => {
14200                self.change_selections(Default::default(), window, cx, |s| {
14201                    s.select_ranges([last.range()]);
14202                });
14203            }
14204            _ => self.select_previous(
14205                &SelectPrevious {
14206                    replace_newest: true,
14207                },
14208                window,
14209                cx,
14210            )?,
14211        }
14212        Ok(())
14213    }
14214
14215    pub fn toggle_comments(
14216        &mut self,
14217        action: &ToggleComments,
14218        window: &mut Window,
14219        cx: &mut Context<Self>,
14220    ) {
14221        if self.read_only(cx) {
14222            return;
14223        }
14224        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14225        let text_layout_details = &self.text_layout_details(window);
14226        self.transact(window, cx, |this, window, cx| {
14227            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14228            let mut edits = Vec::new();
14229            let mut selection_edit_ranges = Vec::new();
14230            let mut last_toggled_row = None;
14231            let snapshot = this.buffer.read(cx).read(cx);
14232            let empty_str: Arc<str> = Arc::default();
14233            let mut suffixes_inserted = Vec::new();
14234            let ignore_indent = action.ignore_indent;
14235
14236            fn comment_prefix_range(
14237                snapshot: &MultiBufferSnapshot,
14238                row: MultiBufferRow,
14239                comment_prefix: &str,
14240                comment_prefix_whitespace: &str,
14241                ignore_indent: bool,
14242            ) -> Range<Point> {
14243                let indent_size = if ignore_indent {
14244                    0
14245                } else {
14246                    snapshot.indent_size_for_line(row).len
14247                };
14248
14249                let start = Point::new(row.0, indent_size);
14250
14251                let mut line_bytes = snapshot
14252                    .bytes_in_range(start..snapshot.max_point())
14253                    .flatten()
14254                    .copied();
14255
14256                // If this line currently begins with the line comment prefix, then record
14257                // the range containing the prefix.
14258                if line_bytes
14259                    .by_ref()
14260                    .take(comment_prefix.len())
14261                    .eq(comment_prefix.bytes())
14262                {
14263                    // Include any whitespace that matches the comment prefix.
14264                    let matching_whitespace_len = line_bytes
14265                        .zip(comment_prefix_whitespace.bytes())
14266                        .take_while(|(a, b)| a == b)
14267                        .count() as u32;
14268                    let end = Point::new(
14269                        start.row,
14270                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14271                    );
14272                    start..end
14273                } else {
14274                    start..start
14275                }
14276            }
14277
14278            fn comment_suffix_range(
14279                snapshot: &MultiBufferSnapshot,
14280                row: MultiBufferRow,
14281                comment_suffix: &str,
14282                comment_suffix_has_leading_space: bool,
14283            ) -> Range<Point> {
14284                let end = Point::new(row.0, snapshot.line_len(row));
14285                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14286
14287                let mut line_end_bytes = snapshot
14288                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14289                    .flatten()
14290                    .copied();
14291
14292                let leading_space_len = if suffix_start_column > 0
14293                    && line_end_bytes.next() == Some(b' ')
14294                    && comment_suffix_has_leading_space
14295                {
14296                    1
14297                } else {
14298                    0
14299                };
14300
14301                // If this line currently begins with the line comment prefix, then record
14302                // the range containing the prefix.
14303                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14304                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14305                    start..end
14306                } else {
14307                    end..end
14308                }
14309            }
14310
14311            // TODO: Handle selections that cross excerpts
14312            for selection in &mut selections {
14313                let start_column = snapshot
14314                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14315                    .len;
14316                let language = if let Some(language) =
14317                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14318                {
14319                    language
14320                } else {
14321                    continue;
14322                };
14323
14324                selection_edit_ranges.clear();
14325
14326                // If multiple selections contain a given row, avoid processing that
14327                // row more than once.
14328                let mut start_row = MultiBufferRow(selection.start.row);
14329                if last_toggled_row == Some(start_row) {
14330                    start_row = start_row.next_row();
14331                }
14332                let end_row =
14333                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14334                        MultiBufferRow(selection.end.row - 1)
14335                    } else {
14336                        MultiBufferRow(selection.end.row)
14337                    };
14338                last_toggled_row = Some(end_row);
14339
14340                if start_row > end_row {
14341                    continue;
14342                }
14343
14344                // If the language has line comments, toggle those.
14345                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14346
14347                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14348                if ignore_indent {
14349                    full_comment_prefixes = full_comment_prefixes
14350                        .into_iter()
14351                        .map(|s| Arc::from(s.trim_end()))
14352                        .collect();
14353                }
14354
14355                if !full_comment_prefixes.is_empty() {
14356                    let first_prefix = full_comment_prefixes
14357                        .first()
14358                        .expect("prefixes is non-empty");
14359                    let prefix_trimmed_lengths = full_comment_prefixes
14360                        .iter()
14361                        .map(|p| p.trim_end_matches(' ').len())
14362                        .collect::<SmallVec<[usize; 4]>>();
14363
14364                    let mut all_selection_lines_are_comments = true;
14365
14366                    for row in start_row.0..=end_row.0 {
14367                        let row = MultiBufferRow(row);
14368                        if start_row < end_row && snapshot.is_line_blank(row) {
14369                            continue;
14370                        }
14371
14372                        let prefix_range = full_comment_prefixes
14373                            .iter()
14374                            .zip(prefix_trimmed_lengths.iter().copied())
14375                            .map(|(prefix, trimmed_prefix_len)| {
14376                                comment_prefix_range(
14377                                    snapshot.deref(),
14378                                    row,
14379                                    &prefix[..trimmed_prefix_len],
14380                                    &prefix[trimmed_prefix_len..],
14381                                    ignore_indent,
14382                                )
14383                            })
14384                            .max_by_key(|range| range.end.column - range.start.column)
14385                            .expect("prefixes is non-empty");
14386
14387                        if prefix_range.is_empty() {
14388                            all_selection_lines_are_comments = false;
14389                        }
14390
14391                        selection_edit_ranges.push(prefix_range);
14392                    }
14393
14394                    if all_selection_lines_are_comments {
14395                        edits.extend(
14396                            selection_edit_ranges
14397                                .iter()
14398                                .cloned()
14399                                .map(|range| (range, empty_str.clone())),
14400                        );
14401                    } else {
14402                        let min_column = selection_edit_ranges
14403                            .iter()
14404                            .map(|range| range.start.column)
14405                            .min()
14406                            .unwrap_or(0);
14407                        edits.extend(selection_edit_ranges.iter().map(|range| {
14408                            let position = Point::new(range.start.row, min_column);
14409                            (position..position, first_prefix.clone())
14410                        }));
14411                    }
14412                } else if let Some(BlockCommentConfig {
14413                    start: full_comment_prefix,
14414                    end: comment_suffix,
14415                    ..
14416                }) = language.block_comment()
14417                {
14418                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14419                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14420                    let prefix_range = comment_prefix_range(
14421                        snapshot.deref(),
14422                        start_row,
14423                        comment_prefix,
14424                        comment_prefix_whitespace,
14425                        ignore_indent,
14426                    );
14427                    let suffix_range = comment_suffix_range(
14428                        snapshot.deref(),
14429                        end_row,
14430                        comment_suffix.trim_start_matches(' '),
14431                        comment_suffix.starts_with(' '),
14432                    );
14433
14434                    if prefix_range.is_empty() || suffix_range.is_empty() {
14435                        edits.push((
14436                            prefix_range.start..prefix_range.start,
14437                            full_comment_prefix.clone(),
14438                        ));
14439                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14440                        suffixes_inserted.push((end_row, comment_suffix.len()));
14441                    } else {
14442                        edits.push((prefix_range, empty_str.clone()));
14443                        edits.push((suffix_range, empty_str.clone()));
14444                    }
14445                } else {
14446                    continue;
14447                }
14448            }
14449
14450            drop(snapshot);
14451            this.buffer.update(cx, |buffer, cx| {
14452                buffer.edit(edits, None, cx);
14453            });
14454
14455            // Adjust selections so that they end before any comment suffixes that
14456            // were inserted.
14457            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14458            let mut selections = this.selections.all::<Point>(cx);
14459            let snapshot = this.buffer.read(cx).read(cx);
14460            for selection in &mut selections {
14461                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14462                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14463                        Ordering::Less => {
14464                            suffixes_inserted.next();
14465                            continue;
14466                        }
14467                        Ordering::Greater => break,
14468                        Ordering::Equal => {
14469                            if selection.end.column == snapshot.line_len(row) {
14470                                if selection.is_empty() {
14471                                    selection.start.column -= suffix_len as u32;
14472                                }
14473                                selection.end.column -= suffix_len as u32;
14474                            }
14475                            break;
14476                        }
14477                    }
14478                }
14479            }
14480
14481            drop(snapshot);
14482            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14483
14484            let selections = this.selections.all::<Point>(cx);
14485            let selections_on_single_row = selections.windows(2).all(|selections| {
14486                selections[0].start.row == selections[1].start.row
14487                    && selections[0].end.row == selections[1].end.row
14488                    && selections[0].start.row == selections[0].end.row
14489            });
14490            let selections_selecting = selections
14491                .iter()
14492                .any(|selection| selection.start != selection.end);
14493            let advance_downwards = action.advance_downwards
14494                && selections_on_single_row
14495                && !selections_selecting
14496                && !matches!(this.mode, EditorMode::SingleLine);
14497
14498            if advance_downwards {
14499                let snapshot = this.buffer.read(cx).snapshot(cx);
14500
14501                this.change_selections(Default::default(), window, cx, |s| {
14502                    s.move_cursors_with(|display_snapshot, display_point, _| {
14503                        let mut point = display_point.to_point(display_snapshot);
14504                        point.row += 1;
14505                        point = snapshot.clip_point(point, Bias::Left);
14506                        let display_point = point.to_display_point(display_snapshot);
14507                        let goal = SelectionGoal::HorizontalPosition(
14508                            display_snapshot
14509                                .x_for_display_point(display_point, text_layout_details)
14510                                .into(),
14511                        );
14512                        (display_point, goal)
14513                    })
14514                });
14515            }
14516        });
14517    }
14518
14519    pub fn select_enclosing_symbol(
14520        &mut self,
14521        _: &SelectEnclosingSymbol,
14522        window: &mut Window,
14523        cx: &mut Context<Self>,
14524    ) {
14525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14526
14527        let buffer = self.buffer.read(cx).snapshot(cx);
14528        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14529
14530        fn update_selection(
14531            selection: &Selection<usize>,
14532            buffer_snap: &MultiBufferSnapshot,
14533        ) -> Option<Selection<usize>> {
14534            let cursor = selection.head();
14535            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14536            for symbol in symbols.iter().rev() {
14537                let start = symbol.range.start.to_offset(buffer_snap);
14538                let end = symbol.range.end.to_offset(buffer_snap);
14539                let new_range = start..end;
14540                if start < selection.start || end > selection.end {
14541                    return Some(Selection {
14542                        id: selection.id,
14543                        start: new_range.start,
14544                        end: new_range.end,
14545                        goal: SelectionGoal::None,
14546                        reversed: selection.reversed,
14547                    });
14548                }
14549            }
14550            None
14551        }
14552
14553        let mut selected_larger_symbol = false;
14554        let new_selections = old_selections
14555            .iter()
14556            .map(|selection| match update_selection(selection, &buffer) {
14557                Some(new_selection) => {
14558                    if new_selection.range() != selection.range() {
14559                        selected_larger_symbol = true;
14560                    }
14561                    new_selection
14562                }
14563                None => selection.clone(),
14564            })
14565            .collect::<Vec<_>>();
14566
14567        if selected_larger_symbol {
14568            self.change_selections(Default::default(), window, cx, |s| {
14569                s.select(new_selections);
14570            });
14571        }
14572    }
14573
14574    pub fn select_larger_syntax_node(
14575        &mut self,
14576        _: &SelectLargerSyntaxNode,
14577        window: &mut Window,
14578        cx: &mut Context<Self>,
14579    ) {
14580        let Some(visible_row_count) = self.visible_row_count() else {
14581            return;
14582        };
14583        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14584        if old_selections.is_empty() {
14585            return;
14586        }
14587
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14589
14590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14591        let buffer = self.buffer.read(cx).snapshot(cx);
14592
14593        let mut selected_larger_node = false;
14594        let mut new_selections = old_selections
14595            .iter()
14596            .map(|selection| {
14597                let old_range = selection.start..selection.end;
14598
14599                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14600                    // manually select word at selection
14601                    if ["string_content", "inline"].contains(&node.kind()) {
14602                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14603                        // ignore if word is already selected
14604                        if !word_range.is_empty() && old_range != word_range {
14605                            let (last_word_range, _) =
14606                                buffer.surrounding_word(old_range.end, false);
14607                            // only select word if start and end point belongs to same word
14608                            if word_range == last_word_range {
14609                                selected_larger_node = true;
14610                                return Selection {
14611                                    id: selection.id,
14612                                    start: word_range.start,
14613                                    end: word_range.end,
14614                                    goal: SelectionGoal::None,
14615                                    reversed: selection.reversed,
14616                                };
14617                            }
14618                        }
14619                    }
14620                }
14621
14622                let mut new_range = old_range.clone();
14623                while let Some((_node, containing_range)) =
14624                    buffer.syntax_ancestor(new_range.clone())
14625                {
14626                    new_range = match containing_range {
14627                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14628                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14629                    };
14630                    if !display_map.intersects_fold(new_range.start)
14631                        && !display_map.intersects_fold(new_range.end)
14632                    {
14633                        break;
14634                    }
14635                }
14636
14637                selected_larger_node |= new_range != old_range;
14638                Selection {
14639                    id: selection.id,
14640                    start: new_range.start,
14641                    end: new_range.end,
14642                    goal: SelectionGoal::None,
14643                    reversed: selection.reversed,
14644                }
14645            })
14646            .collect::<Vec<_>>();
14647
14648        if !selected_larger_node {
14649            return; // don't put this call in the history
14650        }
14651
14652        // scroll based on transformation done to the last selection created by the user
14653        let (last_old, last_new) = old_selections
14654            .last()
14655            .zip(new_selections.last().cloned())
14656            .expect("old_selections isn't empty");
14657
14658        // revert selection
14659        let is_selection_reversed = {
14660            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14661            new_selections.last_mut().expect("checked above").reversed =
14662                should_newest_selection_be_reversed;
14663            should_newest_selection_be_reversed
14664        };
14665
14666        if selected_larger_node {
14667            self.select_syntax_node_history.disable_clearing = true;
14668            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14669                s.select(new_selections.clone());
14670            });
14671            self.select_syntax_node_history.disable_clearing = false;
14672        }
14673
14674        let start_row = last_new.start.to_display_point(&display_map).row().0;
14675        let end_row = last_new.end.to_display_point(&display_map).row().0;
14676        let selection_height = end_row - start_row + 1;
14677        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14678
14679        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14680        let scroll_behavior = if fits_on_the_screen {
14681            self.request_autoscroll(Autoscroll::fit(), cx);
14682            SelectSyntaxNodeScrollBehavior::FitSelection
14683        } else if is_selection_reversed {
14684            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14685            SelectSyntaxNodeScrollBehavior::CursorTop
14686        } else {
14687            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14688            SelectSyntaxNodeScrollBehavior::CursorBottom
14689        };
14690
14691        self.select_syntax_node_history.push((
14692            old_selections,
14693            scroll_behavior,
14694            is_selection_reversed,
14695        ));
14696    }
14697
14698    pub fn select_smaller_syntax_node(
14699        &mut self,
14700        _: &SelectSmallerSyntaxNode,
14701        window: &mut Window,
14702        cx: &mut Context<Self>,
14703    ) {
14704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14705
14706        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14707            self.select_syntax_node_history.pop()
14708        {
14709            if let Some(selection) = selections.last_mut() {
14710                selection.reversed = is_selection_reversed;
14711            }
14712
14713            self.select_syntax_node_history.disable_clearing = true;
14714            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14715                s.select(selections.to_vec());
14716            });
14717            self.select_syntax_node_history.disable_clearing = false;
14718
14719            match scroll_behavior {
14720                SelectSyntaxNodeScrollBehavior::CursorTop => {
14721                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14722                }
14723                SelectSyntaxNodeScrollBehavior::FitSelection => {
14724                    self.request_autoscroll(Autoscroll::fit(), cx);
14725                }
14726                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14727                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14728                }
14729            }
14730        }
14731    }
14732
14733    pub fn unwrap_syntax_node(
14734        &mut self,
14735        _: &UnwrapSyntaxNode,
14736        window: &mut Window,
14737        cx: &mut Context<Self>,
14738    ) {
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740
14741        let buffer = self.buffer.read(cx).snapshot(cx);
14742        let selections = self
14743            .selections
14744            .all::<usize>(cx)
14745            .into_iter()
14746            // subtracting the offset requires sorting
14747            .sorted_by_key(|i| i.start);
14748
14749        let full_edits = selections
14750            .into_iter()
14751            .filter_map(|selection| {
14752                // Only requires two branches once if-let-chains stabilize (#53667)
14753                let child = if !selection.is_empty() {
14754                    selection.range()
14755                } else if let Some((_, ancestor_range)) =
14756                    buffer.syntax_ancestor(selection.start..selection.end)
14757                {
14758                    match ancestor_range {
14759                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14760                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14761                    }
14762                } else {
14763                    selection.range()
14764                };
14765
14766                let mut parent = child.clone();
14767                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14768                    parent = match ancestor_range {
14769                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14770                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14771                    };
14772                    if parent.start < child.start || parent.end > child.end {
14773                        break;
14774                    }
14775                }
14776
14777                if parent == child {
14778                    return None;
14779                }
14780                let text = buffer.text_for_range(child).collect::<String>();
14781                Some((selection.id, parent, text))
14782            })
14783            .collect::<Vec<_>>();
14784
14785        self.transact(window, cx, |this, window, cx| {
14786            this.buffer.update(cx, |buffer, cx| {
14787                buffer.edit(
14788                    full_edits
14789                        .iter()
14790                        .map(|(_, p, t)| (p.clone(), t.clone()))
14791                        .collect::<Vec<_>>(),
14792                    None,
14793                    cx,
14794                );
14795            });
14796            this.change_selections(Default::default(), window, cx, |s| {
14797                let mut offset = 0;
14798                let mut selections = vec![];
14799                for (id, parent, text) in full_edits {
14800                    let start = parent.start - offset;
14801                    offset += parent.len() - text.len();
14802                    selections.push(Selection {
14803                        id,
14804                        start,
14805                        end: start + text.len(),
14806                        reversed: false,
14807                        goal: Default::default(),
14808                    });
14809                }
14810                s.select(selections);
14811            });
14812        });
14813    }
14814
14815    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14816        if !EditorSettings::get_global(cx).gutter.runnables {
14817            self.clear_tasks();
14818            return Task::ready(());
14819        }
14820        let project = self.project().map(Entity::downgrade);
14821        let task_sources = self.lsp_task_sources(cx);
14822        let multi_buffer = self.buffer.downgrade();
14823        cx.spawn_in(window, async move |editor, cx| {
14824            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14825            let Some(project) = project.and_then(|p| p.upgrade()) else {
14826                return;
14827            };
14828            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14829                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14830            }) else {
14831                return;
14832            };
14833
14834            let hide_runnables = project
14835                .update(cx, |project, _| project.is_via_collab())
14836                .unwrap_or(true);
14837            if hide_runnables {
14838                return;
14839            }
14840            let new_rows =
14841                cx.background_spawn({
14842                    let snapshot = display_snapshot.clone();
14843                    async move {
14844                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14845                    }
14846                })
14847                    .await;
14848            let Ok(lsp_tasks) =
14849                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14850            else {
14851                return;
14852            };
14853            let lsp_tasks = lsp_tasks.await;
14854
14855            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14856                lsp_tasks
14857                    .into_iter()
14858                    .flat_map(|(kind, tasks)| {
14859                        tasks.into_iter().filter_map(move |(location, task)| {
14860                            Some((kind.clone(), location?, task))
14861                        })
14862                    })
14863                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14864                        let buffer = location.target.buffer;
14865                        let buffer_snapshot = buffer.read(cx).snapshot();
14866                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14867                            |(excerpt_id, snapshot, _)| {
14868                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14869                                    display_snapshot
14870                                        .buffer_snapshot
14871                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14872                                } else {
14873                                    None
14874                                }
14875                            },
14876                        );
14877                        if let Some(offset) = offset {
14878                            let task_buffer_range =
14879                                location.target.range.to_point(&buffer_snapshot);
14880                            let context_buffer_range =
14881                                task_buffer_range.to_offset(&buffer_snapshot);
14882                            let context_range = BufferOffset(context_buffer_range.start)
14883                                ..BufferOffset(context_buffer_range.end);
14884
14885                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14886                                .or_insert_with(|| RunnableTasks {
14887                                    templates: Vec::new(),
14888                                    offset,
14889                                    column: task_buffer_range.start.column,
14890                                    extra_variables: HashMap::default(),
14891                                    context_range,
14892                                })
14893                                .templates
14894                                .push((kind, task.original_task().clone()));
14895                        }
14896
14897                        acc
14898                    })
14899            }) else {
14900                return;
14901            };
14902
14903            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14904                buffer.language_settings(cx).tasks.prefer_lsp
14905            }) else {
14906                return;
14907            };
14908
14909            let rows = Self::runnable_rows(
14910                project,
14911                display_snapshot,
14912                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14913                new_rows,
14914                cx.clone(),
14915            )
14916            .await;
14917            editor
14918                .update(cx, |editor, _| {
14919                    editor.clear_tasks();
14920                    for (key, mut value) in rows {
14921                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14922                            value.templates.extend(lsp_tasks.templates);
14923                        }
14924
14925                        editor.insert_tasks(key, value);
14926                    }
14927                    for (key, value) in lsp_tasks_by_rows {
14928                        editor.insert_tasks(key, value);
14929                    }
14930                })
14931                .ok();
14932        })
14933    }
14934    fn fetch_runnable_ranges(
14935        snapshot: &DisplaySnapshot,
14936        range: Range<Anchor>,
14937    ) -> Vec<language::RunnableRange> {
14938        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14939    }
14940
14941    fn runnable_rows(
14942        project: Entity<Project>,
14943        snapshot: DisplaySnapshot,
14944        prefer_lsp: bool,
14945        runnable_ranges: Vec<RunnableRange>,
14946        cx: AsyncWindowContext,
14947    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14948        cx.spawn(async move |cx| {
14949            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14950            for mut runnable in runnable_ranges {
14951                let Some(tasks) = cx
14952                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14953                    .ok()
14954                else {
14955                    continue;
14956                };
14957                let mut tasks = tasks.await;
14958
14959                if prefer_lsp {
14960                    tasks.retain(|(task_kind, _)| {
14961                        !matches!(task_kind, TaskSourceKind::Language { .. })
14962                    });
14963                }
14964                if tasks.is_empty() {
14965                    continue;
14966                }
14967
14968                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14969                let Some(row) = snapshot
14970                    .buffer_snapshot
14971                    .buffer_line_for_row(MultiBufferRow(point.row))
14972                    .map(|(_, range)| range.start.row)
14973                else {
14974                    continue;
14975                };
14976
14977                let context_range =
14978                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14979                runnable_rows.push((
14980                    (runnable.buffer_id, row),
14981                    RunnableTasks {
14982                        templates: tasks,
14983                        offset: snapshot
14984                            .buffer_snapshot
14985                            .anchor_before(runnable.run_range.start),
14986                        context_range,
14987                        column: point.column,
14988                        extra_variables: runnable.extra_captures,
14989                    },
14990                ));
14991            }
14992            runnable_rows
14993        })
14994    }
14995
14996    fn templates_with_tags(
14997        project: &Entity<Project>,
14998        runnable: &mut Runnable,
14999        cx: &mut App,
15000    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15001        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15002            let (worktree_id, file) = project
15003                .buffer_for_id(runnable.buffer, cx)
15004                .and_then(|buffer| buffer.read(cx).file())
15005                .map(|file| (file.worktree_id(cx), file.clone()))
15006                .unzip();
15007
15008            (
15009                project.task_store().read(cx).task_inventory().cloned(),
15010                worktree_id,
15011                file,
15012            )
15013        });
15014
15015        let tags = mem::take(&mut runnable.tags);
15016        let language = runnable.language.clone();
15017        cx.spawn(async move |cx| {
15018            let mut templates_with_tags = Vec::new();
15019            if let Some(inventory) = inventory {
15020                for RunnableTag(tag) in tags {
15021                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15022                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15023                    }) else {
15024                        return templates_with_tags;
15025                    };
15026                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15027                        move |(_, template)| {
15028                            template.tags.iter().any(|source_tag| source_tag == &tag)
15029                        },
15030                    ));
15031                }
15032            }
15033            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15034
15035            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15036                // Strongest source wins; if we have worktree tag binding, prefer that to
15037                // global and language bindings;
15038                // if we have a global binding, prefer that to language binding.
15039                let first_mismatch = templates_with_tags
15040                    .iter()
15041                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15042                if let Some(index) = first_mismatch {
15043                    templates_with_tags.truncate(index);
15044                }
15045            }
15046
15047            templates_with_tags
15048        })
15049    }
15050
15051    pub fn move_to_enclosing_bracket(
15052        &mut self,
15053        _: &MoveToEnclosingBracket,
15054        window: &mut Window,
15055        cx: &mut Context<Self>,
15056    ) {
15057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15058        self.change_selections(Default::default(), window, cx, |s| {
15059            s.move_offsets_with(|snapshot, selection| {
15060                let Some(enclosing_bracket_ranges) =
15061                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15062                else {
15063                    return;
15064                };
15065
15066                let mut best_length = usize::MAX;
15067                let mut best_inside = false;
15068                let mut best_in_bracket_range = false;
15069                let mut best_destination = None;
15070                for (open, close) in enclosing_bracket_ranges {
15071                    let close = close.to_inclusive();
15072                    let length = close.end() - open.start;
15073                    let inside = selection.start >= open.end && selection.end <= *close.start();
15074                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15075                        || close.contains(&selection.head());
15076
15077                    // If best is next to a bracket and current isn't, skip
15078                    if !in_bracket_range && best_in_bracket_range {
15079                        continue;
15080                    }
15081
15082                    // Prefer smaller lengths unless best is inside and current isn't
15083                    if length > best_length && (best_inside || !inside) {
15084                        continue;
15085                    }
15086
15087                    best_length = length;
15088                    best_inside = inside;
15089                    best_in_bracket_range = in_bracket_range;
15090                    best_destination = Some(
15091                        if close.contains(&selection.start) && close.contains(&selection.end) {
15092                            if inside { open.end } else { open.start }
15093                        } else if inside {
15094                            *close.start()
15095                        } else {
15096                            *close.end()
15097                        },
15098                    );
15099                }
15100
15101                if let Some(destination) = best_destination {
15102                    selection.collapse_to(destination, SelectionGoal::None);
15103                }
15104            })
15105        });
15106    }
15107
15108    pub fn undo_selection(
15109        &mut self,
15110        _: &UndoSelection,
15111        window: &mut Window,
15112        cx: &mut Context<Self>,
15113    ) {
15114        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15115        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15116            self.selection_history.mode = SelectionHistoryMode::Undoing;
15117            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15118                this.end_selection(window, cx);
15119                this.change_selections(
15120                    SelectionEffects::scroll(Autoscroll::newest()),
15121                    window,
15122                    cx,
15123                    |s| s.select_anchors(entry.selections.to_vec()),
15124                );
15125            });
15126            self.selection_history.mode = SelectionHistoryMode::Normal;
15127
15128            self.select_next_state = entry.select_next_state;
15129            self.select_prev_state = entry.select_prev_state;
15130            self.add_selections_state = entry.add_selections_state;
15131        }
15132    }
15133
15134    pub fn redo_selection(
15135        &mut self,
15136        _: &RedoSelection,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) {
15140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15141        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15142            self.selection_history.mode = SelectionHistoryMode::Redoing;
15143            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15144                this.end_selection(window, cx);
15145                this.change_selections(
15146                    SelectionEffects::scroll(Autoscroll::newest()),
15147                    window,
15148                    cx,
15149                    |s| s.select_anchors(entry.selections.to_vec()),
15150                );
15151            });
15152            self.selection_history.mode = SelectionHistoryMode::Normal;
15153
15154            self.select_next_state = entry.select_next_state;
15155            self.select_prev_state = entry.select_prev_state;
15156            self.add_selections_state = entry.add_selections_state;
15157        }
15158    }
15159
15160    pub fn expand_excerpts(
15161        &mut self,
15162        action: &ExpandExcerpts,
15163        _: &mut Window,
15164        cx: &mut Context<Self>,
15165    ) {
15166        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15167    }
15168
15169    pub fn expand_excerpts_down(
15170        &mut self,
15171        action: &ExpandExcerptsDown,
15172        _: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15176    }
15177
15178    pub fn expand_excerpts_up(
15179        &mut self,
15180        action: &ExpandExcerptsUp,
15181        _: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) {
15184        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15185    }
15186
15187    pub fn expand_excerpts_for_direction(
15188        &mut self,
15189        lines: u32,
15190        direction: ExpandExcerptDirection,
15191
15192        cx: &mut Context<Self>,
15193    ) {
15194        let selections = self.selections.disjoint_anchors();
15195
15196        let lines = if lines == 0 {
15197            EditorSettings::get_global(cx).expand_excerpt_lines
15198        } else {
15199            lines
15200        };
15201
15202        self.buffer.update(cx, |buffer, cx| {
15203            let snapshot = buffer.snapshot(cx);
15204            let mut excerpt_ids = selections
15205                .iter()
15206                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15207                .collect::<Vec<_>>();
15208            excerpt_ids.sort();
15209            excerpt_ids.dedup();
15210            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15211        })
15212    }
15213
15214    pub fn expand_excerpt(
15215        &mut self,
15216        excerpt: ExcerptId,
15217        direction: ExpandExcerptDirection,
15218        window: &mut Window,
15219        cx: &mut Context<Self>,
15220    ) {
15221        let current_scroll_position = self.scroll_position(cx);
15222        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15223        let mut should_scroll_up = false;
15224
15225        if direction == ExpandExcerptDirection::Down {
15226            let multi_buffer = self.buffer.read(cx);
15227            let snapshot = multi_buffer.snapshot(cx);
15228            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15229                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15230                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15231            {
15232                let buffer_snapshot = buffer.read(cx).snapshot();
15233                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15234                let last_row = buffer_snapshot.max_point().row;
15235                let lines_below = last_row.saturating_sub(excerpt_end_row);
15236                should_scroll_up = lines_below >= lines_to_expand;
15237            }
15238        }
15239
15240        self.buffer.update(cx, |buffer, cx| {
15241            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15242        });
15243
15244        if should_scroll_up {
15245            let new_scroll_position =
15246                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15247            self.set_scroll_position(new_scroll_position, window, cx);
15248        }
15249    }
15250
15251    pub fn go_to_singleton_buffer_point(
15252        &mut self,
15253        point: Point,
15254        window: &mut Window,
15255        cx: &mut Context<Self>,
15256    ) {
15257        self.go_to_singleton_buffer_range(point..point, window, cx);
15258    }
15259
15260    pub fn go_to_singleton_buffer_range(
15261        &mut self,
15262        range: Range<Point>,
15263        window: &mut Window,
15264        cx: &mut Context<Self>,
15265    ) {
15266        let multibuffer = self.buffer().read(cx);
15267        let Some(buffer) = multibuffer.as_singleton() else {
15268            return;
15269        };
15270        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15271            return;
15272        };
15273        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15274            return;
15275        };
15276        self.change_selections(
15277            SelectionEffects::default().nav_history(true),
15278            window,
15279            cx,
15280            |s| s.select_anchor_ranges([start..end]),
15281        );
15282    }
15283
15284    pub fn go_to_diagnostic(
15285        &mut self,
15286        action: &GoToDiagnostic,
15287        window: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) {
15290        if !self.diagnostics_enabled() {
15291            return;
15292        }
15293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15294        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15295    }
15296
15297    pub fn go_to_prev_diagnostic(
15298        &mut self,
15299        action: &GoToPreviousDiagnostic,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        if !self.diagnostics_enabled() {
15304            return;
15305        }
15306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15307        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15308    }
15309
15310    pub fn go_to_diagnostic_impl(
15311        &mut self,
15312        direction: Direction,
15313        severity: GoToDiagnosticSeverityFilter,
15314        window: &mut Window,
15315        cx: &mut Context<Self>,
15316    ) {
15317        let buffer = self.buffer.read(cx).snapshot(cx);
15318        let selection = self.selections.newest::<usize>(cx);
15319
15320        let mut active_group_id = None;
15321        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15322            && active_group.active_range.start.to_offset(&buffer) == selection.start
15323        {
15324            active_group_id = Some(active_group.group_id);
15325        }
15326
15327        fn filtered(
15328            snapshot: EditorSnapshot,
15329            severity: GoToDiagnosticSeverityFilter,
15330            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15331        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15332            diagnostics
15333                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15334                .filter(|entry| entry.range.start != entry.range.end)
15335                .filter(|entry| !entry.diagnostic.is_unnecessary)
15336                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15337        }
15338
15339        let snapshot = self.snapshot(window, cx);
15340        let before = filtered(
15341            snapshot.clone(),
15342            severity,
15343            buffer
15344                .diagnostics_in_range(0..selection.start)
15345                .filter(|entry| entry.range.start <= selection.start),
15346        );
15347        let after = filtered(
15348            snapshot,
15349            severity,
15350            buffer
15351                .diagnostics_in_range(selection.start..buffer.len())
15352                .filter(|entry| entry.range.start >= selection.start),
15353        );
15354
15355        let mut found: Option<DiagnosticEntry<usize>> = None;
15356        if direction == Direction::Prev {
15357            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15358            {
15359                for diagnostic in prev_diagnostics.into_iter().rev() {
15360                    if diagnostic.range.start != selection.start
15361                        || active_group_id
15362                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15363                    {
15364                        found = Some(diagnostic);
15365                        break 'outer;
15366                    }
15367                }
15368            }
15369        } else {
15370            for diagnostic in after.chain(before) {
15371                if diagnostic.range.start != selection.start
15372                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15373                {
15374                    found = Some(diagnostic);
15375                    break;
15376                }
15377            }
15378        }
15379        let Some(next_diagnostic) = found else {
15380            return;
15381        };
15382
15383        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15384        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15385            return;
15386        };
15387        self.change_selections(Default::default(), window, cx, |s| {
15388            s.select_ranges(vec![
15389                next_diagnostic.range.start..next_diagnostic.range.start,
15390            ])
15391        });
15392        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15393        self.refresh_edit_prediction(false, true, window, cx);
15394    }
15395
15396    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15398        let snapshot = self.snapshot(window, cx);
15399        let selection = self.selections.newest::<Point>(cx);
15400        self.go_to_hunk_before_or_after_position(
15401            &snapshot,
15402            selection.head(),
15403            Direction::Next,
15404            window,
15405            cx,
15406        );
15407    }
15408
15409    pub fn go_to_hunk_before_or_after_position(
15410        &mut self,
15411        snapshot: &EditorSnapshot,
15412        position: Point,
15413        direction: Direction,
15414        window: &mut Window,
15415        cx: &mut Context<Editor>,
15416    ) {
15417        let row = if direction == Direction::Next {
15418            self.hunk_after_position(snapshot, position)
15419                .map(|hunk| hunk.row_range.start)
15420        } else {
15421            self.hunk_before_position(snapshot, position)
15422        };
15423
15424        if let Some(row) = row {
15425            let destination = Point::new(row.0, 0);
15426            let autoscroll = Autoscroll::center();
15427
15428            self.unfold_ranges(&[destination..destination], false, false, cx);
15429            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15430                s.select_ranges([destination..destination]);
15431            });
15432        }
15433    }
15434
15435    fn hunk_after_position(
15436        &mut self,
15437        snapshot: &EditorSnapshot,
15438        position: Point,
15439    ) -> Option<MultiBufferDiffHunk> {
15440        snapshot
15441            .buffer_snapshot
15442            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15443            .find(|hunk| hunk.row_range.start.0 > position.row)
15444            .or_else(|| {
15445                snapshot
15446                    .buffer_snapshot
15447                    .diff_hunks_in_range(Point::zero()..position)
15448                    .find(|hunk| hunk.row_range.end.0 < position.row)
15449            })
15450    }
15451
15452    fn go_to_prev_hunk(
15453        &mut self,
15454        _: &GoToPreviousHunk,
15455        window: &mut Window,
15456        cx: &mut Context<Self>,
15457    ) {
15458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15459        let snapshot = self.snapshot(window, cx);
15460        let selection = self.selections.newest::<Point>(cx);
15461        self.go_to_hunk_before_or_after_position(
15462            &snapshot,
15463            selection.head(),
15464            Direction::Prev,
15465            window,
15466            cx,
15467        );
15468    }
15469
15470    fn hunk_before_position(
15471        &mut self,
15472        snapshot: &EditorSnapshot,
15473        position: Point,
15474    ) -> Option<MultiBufferRow> {
15475        snapshot
15476            .buffer_snapshot
15477            .diff_hunk_before(position)
15478            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15479    }
15480
15481    fn go_to_next_change(
15482        &mut self,
15483        _: &GoToNextChange,
15484        window: &mut Window,
15485        cx: &mut Context<Self>,
15486    ) {
15487        if let Some(selections) = self
15488            .change_list
15489            .next_change(1, Direction::Next)
15490            .map(|s| s.to_vec())
15491        {
15492            self.change_selections(Default::default(), window, cx, |s| {
15493                let map = s.display_map();
15494                s.select_display_ranges(selections.iter().map(|a| {
15495                    let point = a.to_display_point(&map);
15496                    point..point
15497                }))
15498            })
15499        }
15500    }
15501
15502    fn go_to_previous_change(
15503        &mut self,
15504        _: &GoToPreviousChange,
15505        window: &mut Window,
15506        cx: &mut Context<Self>,
15507    ) {
15508        if let Some(selections) = self
15509            .change_list
15510            .next_change(1, Direction::Prev)
15511            .map(|s| s.to_vec())
15512        {
15513            self.change_selections(Default::default(), window, cx, |s| {
15514                let map = s.display_map();
15515                s.select_display_ranges(selections.iter().map(|a| {
15516                    let point = a.to_display_point(&map);
15517                    point..point
15518                }))
15519            })
15520        }
15521    }
15522
15523    fn go_to_line<T: 'static>(
15524        &mut self,
15525        position: Anchor,
15526        highlight_color: Option<Hsla>,
15527        window: &mut Window,
15528        cx: &mut Context<Self>,
15529    ) {
15530        let snapshot = self.snapshot(window, cx).display_snapshot;
15531        let position = position.to_point(&snapshot.buffer_snapshot);
15532        let start = snapshot
15533            .buffer_snapshot
15534            .clip_point(Point::new(position.row, 0), Bias::Left);
15535        let end = start + Point::new(1, 0);
15536        let start = snapshot.buffer_snapshot.anchor_before(start);
15537        let end = snapshot.buffer_snapshot.anchor_before(end);
15538
15539        self.highlight_rows::<T>(
15540            start..end,
15541            highlight_color
15542                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15543            Default::default(),
15544            cx,
15545        );
15546
15547        if self.buffer.read(cx).is_singleton() {
15548            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15549        }
15550    }
15551
15552    pub fn go_to_definition(
15553        &mut self,
15554        _: &GoToDefinition,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) -> Task<Result<Navigated>> {
15558        let definition =
15559            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15560        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15561        cx.spawn_in(window, async move |editor, cx| {
15562            if definition.await? == Navigated::Yes {
15563                return Ok(Navigated::Yes);
15564            }
15565            match fallback_strategy {
15566                GoToDefinitionFallback::None => Ok(Navigated::No),
15567                GoToDefinitionFallback::FindAllReferences => {
15568                    match editor.update_in(cx, |editor, window, cx| {
15569                        editor.find_all_references(&FindAllReferences, window, cx)
15570                    })? {
15571                        Some(references) => references.await,
15572                        None => Ok(Navigated::No),
15573                    }
15574                }
15575            }
15576        })
15577    }
15578
15579    pub fn go_to_declaration(
15580        &mut self,
15581        _: &GoToDeclaration,
15582        window: &mut Window,
15583        cx: &mut Context<Self>,
15584    ) -> Task<Result<Navigated>> {
15585        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15586    }
15587
15588    pub fn go_to_declaration_split(
15589        &mut self,
15590        _: &GoToDeclaration,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) -> Task<Result<Navigated>> {
15594        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15595    }
15596
15597    pub fn go_to_implementation(
15598        &mut self,
15599        _: &GoToImplementation,
15600        window: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) -> Task<Result<Navigated>> {
15603        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15604    }
15605
15606    pub fn go_to_implementation_split(
15607        &mut self,
15608        _: &GoToImplementationSplit,
15609        window: &mut Window,
15610        cx: &mut Context<Self>,
15611    ) -> Task<Result<Navigated>> {
15612        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15613    }
15614
15615    pub fn go_to_type_definition(
15616        &mut self,
15617        _: &GoToTypeDefinition,
15618        window: &mut Window,
15619        cx: &mut Context<Self>,
15620    ) -> Task<Result<Navigated>> {
15621        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15622    }
15623
15624    pub fn go_to_definition_split(
15625        &mut self,
15626        _: &GoToDefinitionSplit,
15627        window: &mut Window,
15628        cx: &mut Context<Self>,
15629    ) -> Task<Result<Navigated>> {
15630        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15631    }
15632
15633    pub fn go_to_type_definition_split(
15634        &mut self,
15635        _: &GoToTypeDefinitionSplit,
15636        window: &mut Window,
15637        cx: &mut Context<Self>,
15638    ) -> Task<Result<Navigated>> {
15639        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15640    }
15641
15642    fn go_to_definition_of_kind(
15643        &mut self,
15644        kind: GotoDefinitionKind,
15645        split: bool,
15646        window: &mut Window,
15647        cx: &mut Context<Self>,
15648    ) -> Task<Result<Navigated>> {
15649        let Some(provider) = self.semantics_provider.clone() else {
15650            return Task::ready(Ok(Navigated::No));
15651        };
15652        let head = self.selections.newest::<usize>(cx).head();
15653        let buffer = self.buffer.read(cx);
15654        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15655            return Task::ready(Ok(Navigated::No));
15656        };
15657        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15658            return Task::ready(Ok(Navigated::No));
15659        };
15660
15661        cx.spawn_in(window, async move |editor, cx| {
15662            let definitions = definitions.await?;
15663            let navigated = editor
15664                .update_in(cx, |editor, window, cx| {
15665                    editor.navigate_to_hover_links(
15666                        Some(kind),
15667                        definitions
15668                            .into_iter()
15669                            .filter(|location| {
15670                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15671                            })
15672                            .map(HoverLink::Text)
15673                            .collect::<Vec<_>>(),
15674                        split,
15675                        window,
15676                        cx,
15677                    )
15678                })?
15679                .await?;
15680            anyhow::Ok(navigated)
15681        })
15682    }
15683
15684    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15685        let selection = self.selections.newest_anchor();
15686        let head = selection.head();
15687        let tail = selection.tail();
15688
15689        let Some((buffer, start_position)) =
15690            self.buffer.read(cx).text_anchor_for_position(head, cx)
15691        else {
15692            return;
15693        };
15694
15695        let end_position = if head != tail {
15696            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15697                return;
15698            };
15699            Some(pos)
15700        } else {
15701            None
15702        };
15703
15704        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15705            let url = if let Some(end_pos) = end_position {
15706                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15707            } else {
15708                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15709            };
15710
15711            if let Some(url) = url {
15712                editor.update(cx, |_, cx| {
15713                    cx.open_url(&url);
15714                })
15715            } else {
15716                Ok(())
15717            }
15718        });
15719
15720        url_finder.detach();
15721    }
15722
15723    pub fn open_selected_filename(
15724        &mut self,
15725        _: &OpenSelectedFilename,
15726        window: &mut Window,
15727        cx: &mut Context<Self>,
15728    ) {
15729        let Some(workspace) = self.workspace() else {
15730            return;
15731        };
15732
15733        let position = self.selections.newest_anchor().head();
15734
15735        let Some((buffer, buffer_position)) =
15736            self.buffer.read(cx).text_anchor_for_position(position, cx)
15737        else {
15738            return;
15739        };
15740
15741        let project = self.project.clone();
15742
15743        cx.spawn_in(window, async move |_, cx| {
15744            let result = find_file(&buffer, project, buffer_position, cx).await;
15745
15746            if let Some((_, path)) = result {
15747                workspace
15748                    .update_in(cx, |workspace, window, cx| {
15749                        workspace.open_resolved_path(path, window, cx)
15750                    })?
15751                    .await?;
15752            }
15753            anyhow::Ok(())
15754        })
15755        .detach();
15756    }
15757
15758    pub(crate) fn navigate_to_hover_links(
15759        &mut self,
15760        kind: Option<GotoDefinitionKind>,
15761        definitions: Vec<HoverLink>,
15762        split: bool,
15763        window: &mut Window,
15764        cx: &mut Context<Editor>,
15765    ) -> Task<Result<Navigated>> {
15766        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15767        let mut first_url_or_file = None;
15768        let definitions: Vec<_> = definitions
15769            .into_iter()
15770            .filter_map(|def| match def {
15771                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15772                HoverLink::InlayHint(lsp_location, server_id) => {
15773                    let computation =
15774                        self.compute_target_location(lsp_location, server_id, window, cx);
15775                    Some(cx.background_spawn(computation))
15776                }
15777                HoverLink::Url(url) => {
15778                    first_url_or_file = Some(Either::Left(url));
15779                    None
15780                }
15781                HoverLink::File(path) => {
15782                    first_url_or_file = Some(Either::Right(path));
15783                    None
15784                }
15785            })
15786            .collect();
15787
15788        let workspace = self.workspace();
15789
15790        cx.spawn_in(window, async move |editor, acx| {
15791            let mut locations: Vec<Location> = future::join_all(definitions)
15792                .await
15793                .into_iter()
15794                .filter_map(|location| location.transpose())
15795                .collect::<Result<_>>()
15796                .context("location tasks")?;
15797
15798            if locations.len() > 1 {
15799                let Some(workspace) = workspace else {
15800                    return Ok(Navigated::No);
15801                };
15802
15803                let tab_kind = match kind {
15804                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15805                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15806                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15807                    Some(GotoDefinitionKind::Type) => "Types",
15808                };
15809                let title = editor
15810                    .update_in(acx, |_, _, cx| {
15811                        let target = locations
15812                            .iter()
15813                            .map(|location| {
15814                                location
15815                                    .buffer
15816                                    .read(cx)
15817                                    .text_for_range(location.range.clone())
15818                                    .collect::<String>()
15819                            })
15820                            .filter(|text| !text.contains('\n'))
15821                            .unique()
15822                            .take(3)
15823                            .join(", ");
15824                        if target.is_empty() {
15825                            tab_kind.to_owned()
15826                        } else {
15827                            format!("{tab_kind} for {target}")
15828                        }
15829                    })
15830                    .context("buffer title")?;
15831
15832                let opened = workspace
15833                    .update_in(acx, |workspace, window, cx| {
15834                        Self::open_locations_in_multibuffer(
15835                            workspace,
15836                            locations,
15837                            title,
15838                            split,
15839                            MultibufferSelectionMode::First,
15840                            window,
15841                            cx,
15842                        )
15843                    })
15844                    .is_ok();
15845
15846                anyhow::Ok(Navigated::from_bool(opened))
15847            } else if locations.is_empty() {
15848                // If there is one definition, just open it directly
15849                match first_url_or_file {
15850                    Some(Either::Left(url)) => {
15851                        acx.update(|_, cx| cx.open_url(&url))?;
15852                        Ok(Navigated::Yes)
15853                    }
15854                    Some(Either::Right(path)) => {
15855                        let Some(workspace) = workspace else {
15856                            return Ok(Navigated::No);
15857                        };
15858
15859                        workspace
15860                            .update_in(acx, |workspace, window, cx| {
15861                                workspace.open_resolved_path(path, window, cx)
15862                            })?
15863                            .await?;
15864                        Ok(Navigated::Yes)
15865                    }
15866                    None => Ok(Navigated::No),
15867                }
15868            } else {
15869                let Some(workspace) = workspace else {
15870                    return Ok(Navigated::No);
15871                };
15872
15873                let target = locations.pop().unwrap();
15874                editor.update_in(acx, |editor, window, cx| {
15875                    let pane = workspace.read(cx).active_pane().clone();
15876
15877                    let range = target.range.to_point(target.buffer.read(cx));
15878                    let range = editor.range_for_match(&range);
15879                    let range = collapse_multiline_range(range);
15880
15881                    if !split
15882                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15883                    {
15884                        editor.go_to_singleton_buffer_range(range, window, cx);
15885                    } else {
15886                        window.defer(cx, move |window, cx| {
15887                            let target_editor: Entity<Self> =
15888                                workspace.update(cx, |workspace, cx| {
15889                                    let pane = if split {
15890                                        workspace.adjacent_pane(window, cx)
15891                                    } else {
15892                                        workspace.active_pane().clone()
15893                                    };
15894
15895                                    workspace.open_project_item(
15896                                        pane,
15897                                        target.buffer.clone(),
15898                                        true,
15899                                        true,
15900                                        window,
15901                                        cx,
15902                                    )
15903                                });
15904                            target_editor.update(cx, |target_editor, cx| {
15905                                // When selecting a definition in a different buffer, disable the nav history
15906                                // to avoid creating a history entry at the previous cursor location.
15907                                pane.update(cx, |pane, _| pane.disable_history());
15908                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15909                                pane.update(cx, |pane, _| pane.enable_history());
15910                            });
15911                        });
15912                    }
15913                    Navigated::Yes
15914                })
15915            }
15916        })
15917    }
15918
15919    fn compute_target_location(
15920        &self,
15921        lsp_location: lsp::Location,
15922        server_id: LanguageServerId,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) -> Task<anyhow::Result<Option<Location>>> {
15926        let Some(project) = self.project.clone() else {
15927            return Task::ready(Ok(None));
15928        };
15929
15930        cx.spawn_in(window, async move |editor, cx| {
15931            let location_task = editor.update(cx, |_, cx| {
15932                project.update(cx, |project, cx| {
15933                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15934                })
15935            })?;
15936            let location = Some({
15937                let target_buffer_handle = location_task.await.context("open local buffer")?;
15938                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15939                    let target_start = target_buffer
15940                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15941                    let target_end = target_buffer
15942                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15943                    target_buffer.anchor_after(target_start)
15944                        ..target_buffer.anchor_before(target_end)
15945                })?;
15946                Location {
15947                    buffer: target_buffer_handle,
15948                    range,
15949                }
15950            });
15951            Ok(location)
15952        })
15953    }
15954
15955    pub fn find_all_references(
15956        &mut self,
15957        _: &FindAllReferences,
15958        window: &mut Window,
15959        cx: &mut Context<Self>,
15960    ) -> Option<Task<Result<Navigated>>> {
15961        let selection = self.selections.newest::<usize>(cx);
15962        let multi_buffer = self.buffer.read(cx);
15963        let head = selection.head();
15964
15965        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15966        let head_anchor = multi_buffer_snapshot.anchor_at(
15967            head,
15968            if head < selection.tail() {
15969                Bias::Right
15970            } else {
15971                Bias::Left
15972            },
15973        );
15974
15975        match self
15976            .find_all_references_task_sources
15977            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15978        {
15979            Ok(_) => {
15980                log::info!(
15981                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15982                );
15983                return None;
15984            }
15985            Err(i) => {
15986                self.find_all_references_task_sources.insert(i, head_anchor);
15987            }
15988        }
15989
15990        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15991        let workspace = self.workspace()?;
15992        let project = workspace.read(cx).project().clone();
15993        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15994        Some(cx.spawn_in(window, async move |editor, cx| {
15995            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15996                if let Ok(i) = editor
15997                    .find_all_references_task_sources
15998                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15999                {
16000                    editor.find_all_references_task_sources.remove(i);
16001                }
16002            });
16003
16004            let locations = references.await?;
16005            if locations.is_empty() {
16006                return anyhow::Ok(Navigated::No);
16007            }
16008
16009            workspace.update_in(cx, |workspace, window, cx| {
16010                let target = locations
16011                    .iter()
16012                    .map(|location| {
16013                        location
16014                            .buffer
16015                            .read(cx)
16016                            .text_for_range(location.range.clone())
16017                            .collect::<String>()
16018                    })
16019                    .filter(|text| !text.contains('\n'))
16020                    .unique()
16021                    .take(3)
16022                    .join(", ");
16023                let title = if target.is_empty() {
16024                    "References".to_owned()
16025                } else {
16026                    format!("References to {target}")
16027                };
16028                Self::open_locations_in_multibuffer(
16029                    workspace,
16030                    locations,
16031                    title,
16032                    false,
16033                    MultibufferSelectionMode::First,
16034                    window,
16035                    cx,
16036                );
16037                Navigated::Yes
16038            })
16039        }))
16040    }
16041
16042    /// Opens a multibuffer with the given project locations in it
16043    pub fn open_locations_in_multibuffer(
16044        workspace: &mut Workspace,
16045        mut locations: Vec<Location>,
16046        title: String,
16047        split: bool,
16048        multibuffer_selection_mode: MultibufferSelectionMode,
16049        window: &mut Window,
16050        cx: &mut Context<Workspace>,
16051    ) {
16052        if locations.is_empty() {
16053            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16054            return;
16055        }
16056
16057        // If there are multiple definitions, open them in a multibuffer
16058        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16059        let mut locations = locations.into_iter().peekable();
16060        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16061        let capability = workspace.project().read(cx).capability();
16062
16063        let excerpt_buffer = cx.new(|cx| {
16064            let mut multibuffer = MultiBuffer::new(capability);
16065            while let Some(location) = locations.next() {
16066                let buffer = location.buffer.read(cx);
16067                let mut ranges_for_buffer = Vec::new();
16068                let range = location.range.to_point(buffer);
16069                ranges_for_buffer.push(range.clone());
16070
16071                while let Some(next_location) = locations.peek() {
16072                    if next_location.buffer == location.buffer {
16073                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16074                        locations.next();
16075                    } else {
16076                        break;
16077                    }
16078                }
16079
16080                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16081                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16082                    PathKey::for_buffer(&location.buffer, cx),
16083                    location.buffer.clone(),
16084                    ranges_for_buffer,
16085                    DEFAULT_MULTIBUFFER_CONTEXT,
16086                    cx,
16087                );
16088                ranges.extend(new_ranges)
16089            }
16090
16091            multibuffer.with_title(title)
16092        });
16093
16094        let editor = cx.new(|cx| {
16095            Editor::for_multibuffer(
16096                excerpt_buffer,
16097                Some(workspace.project().clone()),
16098                window,
16099                cx,
16100            )
16101        });
16102        editor.update(cx, |editor, cx| {
16103            match multibuffer_selection_mode {
16104                MultibufferSelectionMode::First => {
16105                    if let Some(first_range) = ranges.first() {
16106                        editor.change_selections(
16107                            SelectionEffects::no_scroll(),
16108                            window,
16109                            cx,
16110                            |selections| {
16111                                selections.clear_disjoint();
16112                                selections
16113                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16114                            },
16115                        );
16116                    }
16117                    editor.highlight_background::<Self>(
16118                        &ranges,
16119                        |theme| theme.colors().editor_highlighted_line_background,
16120                        cx,
16121                    );
16122                }
16123                MultibufferSelectionMode::All => {
16124                    editor.change_selections(
16125                        SelectionEffects::no_scroll(),
16126                        window,
16127                        cx,
16128                        |selections| {
16129                            selections.clear_disjoint();
16130                            selections.select_anchor_ranges(ranges);
16131                        },
16132                    );
16133                }
16134            }
16135            editor.register_buffers_with_language_servers(cx);
16136        });
16137
16138        let item = Box::new(editor);
16139        let item_id = item.item_id();
16140
16141        if split {
16142            workspace.split_item(SplitDirection::Right, item, window, cx);
16143        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16144            let (preview_item_id, preview_item_idx) =
16145                workspace.active_pane().read_with(cx, |pane, _| {
16146                    (pane.preview_item_id(), pane.preview_item_idx())
16147                });
16148
16149            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16150
16151            if let Some(preview_item_id) = preview_item_id {
16152                workspace.active_pane().update(cx, |pane, cx| {
16153                    pane.remove_item(preview_item_id, false, false, window, cx);
16154                });
16155            }
16156        } else {
16157            workspace.add_item_to_active_pane(item, None, true, window, cx);
16158        }
16159        workspace.active_pane().update(cx, |pane, cx| {
16160            pane.set_preview_item_id(Some(item_id), cx);
16161        });
16162    }
16163
16164    pub fn rename(
16165        &mut self,
16166        _: &Rename,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Option<Task<Result<()>>> {
16170        use language::ToOffset as _;
16171
16172        let provider = self.semantics_provider.clone()?;
16173        let selection = self.selections.newest_anchor().clone();
16174        let (cursor_buffer, cursor_buffer_position) = self
16175            .buffer
16176            .read(cx)
16177            .text_anchor_for_position(selection.head(), cx)?;
16178        let (tail_buffer, cursor_buffer_position_end) = self
16179            .buffer
16180            .read(cx)
16181            .text_anchor_for_position(selection.tail(), cx)?;
16182        if tail_buffer != cursor_buffer {
16183            return None;
16184        }
16185
16186        let snapshot = cursor_buffer.read(cx).snapshot();
16187        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16188        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16189        let prepare_rename = provider
16190            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16191            .unwrap_or_else(|| Task::ready(Ok(None)));
16192        drop(snapshot);
16193
16194        Some(cx.spawn_in(window, async move |this, cx| {
16195            let rename_range = if let Some(range) = prepare_rename.await? {
16196                Some(range)
16197            } else {
16198                this.update(cx, |this, cx| {
16199                    let buffer = this.buffer.read(cx).snapshot(cx);
16200                    let mut buffer_highlights = this
16201                        .document_highlights_for_position(selection.head(), &buffer)
16202                        .filter(|highlight| {
16203                            highlight.start.excerpt_id == selection.head().excerpt_id
16204                                && highlight.end.excerpt_id == selection.head().excerpt_id
16205                        });
16206                    buffer_highlights
16207                        .next()
16208                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16209                })?
16210            };
16211            if let Some(rename_range) = rename_range {
16212                this.update_in(cx, |this, window, cx| {
16213                    let snapshot = cursor_buffer.read(cx).snapshot();
16214                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16215                    let cursor_offset_in_rename_range =
16216                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16217                    let cursor_offset_in_rename_range_end =
16218                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16219
16220                    this.take_rename(false, window, cx);
16221                    let buffer = this.buffer.read(cx).read(cx);
16222                    let cursor_offset = selection.head().to_offset(&buffer);
16223                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16224                    let rename_end = rename_start + rename_buffer_range.len();
16225                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16226                    let mut old_highlight_id = None;
16227                    let old_name: Arc<str> = buffer
16228                        .chunks(rename_start..rename_end, true)
16229                        .map(|chunk| {
16230                            if old_highlight_id.is_none() {
16231                                old_highlight_id = chunk.syntax_highlight_id;
16232                            }
16233                            chunk.text
16234                        })
16235                        .collect::<String>()
16236                        .into();
16237
16238                    drop(buffer);
16239
16240                    // Position the selection in the rename editor so that it matches the current selection.
16241                    this.show_local_selections = false;
16242                    let rename_editor = cx.new(|cx| {
16243                        let mut editor = Editor::single_line(window, cx);
16244                        editor.buffer.update(cx, |buffer, cx| {
16245                            buffer.edit([(0..0, old_name.clone())], None, cx)
16246                        });
16247                        let rename_selection_range = match cursor_offset_in_rename_range
16248                            .cmp(&cursor_offset_in_rename_range_end)
16249                        {
16250                            Ordering::Equal => {
16251                                editor.select_all(&SelectAll, window, cx);
16252                                return editor;
16253                            }
16254                            Ordering::Less => {
16255                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16256                            }
16257                            Ordering::Greater => {
16258                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16259                            }
16260                        };
16261                        if rename_selection_range.end > old_name.len() {
16262                            editor.select_all(&SelectAll, window, cx);
16263                        } else {
16264                            editor.change_selections(Default::default(), window, cx, |s| {
16265                                s.select_ranges([rename_selection_range]);
16266                            });
16267                        }
16268                        editor
16269                    });
16270                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16271                        if e == &EditorEvent::Focused {
16272                            cx.emit(EditorEvent::FocusedIn)
16273                        }
16274                    })
16275                    .detach();
16276
16277                    let write_highlights =
16278                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16279                    let read_highlights =
16280                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16281                    let ranges = write_highlights
16282                        .iter()
16283                        .flat_map(|(_, ranges)| ranges.iter())
16284                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16285                        .cloned()
16286                        .collect();
16287
16288                    this.highlight_text::<Rename>(
16289                        ranges,
16290                        HighlightStyle {
16291                            fade_out: Some(0.6),
16292                            ..Default::default()
16293                        },
16294                        cx,
16295                    );
16296                    let rename_focus_handle = rename_editor.focus_handle(cx);
16297                    window.focus(&rename_focus_handle);
16298                    let block_id = this.insert_blocks(
16299                        [BlockProperties {
16300                            style: BlockStyle::Flex,
16301                            placement: BlockPlacement::Below(range.start),
16302                            height: Some(1),
16303                            render: Arc::new({
16304                                let rename_editor = rename_editor.clone();
16305                                move |cx: &mut BlockContext| {
16306                                    let mut text_style = cx.editor_style.text.clone();
16307                                    if let Some(highlight_style) = old_highlight_id
16308                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16309                                    {
16310                                        text_style = text_style.highlight(highlight_style);
16311                                    }
16312                                    div()
16313                                        .block_mouse_except_scroll()
16314                                        .pl(cx.anchor_x)
16315                                        .child(EditorElement::new(
16316                                            &rename_editor,
16317                                            EditorStyle {
16318                                                background: cx.theme().system().transparent,
16319                                                local_player: cx.editor_style.local_player,
16320                                                text: text_style,
16321                                                scrollbar_width: cx.editor_style.scrollbar_width,
16322                                                syntax: cx.editor_style.syntax.clone(),
16323                                                status: cx.editor_style.status.clone(),
16324                                                inlay_hints_style: HighlightStyle {
16325                                                    font_weight: Some(FontWeight::BOLD),
16326                                                    ..make_inlay_hints_style(cx.app)
16327                                                },
16328                                                edit_prediction_styles: make_suggestion_styles(
16329                                                    cx.app,
16330                                                ),
16331                                                ..EditorStyle::default()
16332                                            },
16333                                        ))
16334                                        .into_any_element()
16335                                }
16336                            }),
16337                            priority: 0,
16338                        }],
16339                        Some(Autoscroll::fit()),
16340                        cx,
16341                    )[0];
16342                    this.pending_rename = Some(RenameState {
16343                        range,
16344                        old_name,
16345                        editor: rename_editor,
16346                        block_id,
16347                    });
16348                })?;
16349            }
16350
16351            Ok(())
16352        }))
16353    }
16354
16355    pub fn confirm_rename(
16356        &mut self,
16357        _: &ConfirmRename,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Option<Task<Result<()>>> {
16361        let rename = self.take_rename(false, window, cx)?;
16362        let workspace = self.workspace()?.downgrade();
16363        let (buffer, start) = self
16364            .buffer
16365            .read(cx)
16366            .text_anchor_for_position(rename.range.start, cx)?;
16367        let (end_buffer, _) = self
16368            .buffer
16369            .read(cx)
16370            .text_anchor_for_position(rename.range.end, cx)?;
16371        if buffer != end_buffer {
16372            return None;
16373        }
16374
16375        let old_name = rename.old_name;
16376        let new_name = rename.editor.read(cx).text(cx);
16377
16378        let rename = self.semantics_provider.as_ref()?.perform_rename(
16379            &buffer,
16380            start,
16381            new_name.clone(),
16382            cx,
16383        )?;
16384
16385        Some(cx.spawn_in(window, async move |editor, cx| {
16386            let project_transaction = rename.await?;
16387            Self::open_project_transaction(
16388                &editor,
16389                workspace,
16390                project_transaction,
16391                format!("Rename: {}{}", old_name, new_name),
16392                cx,
16393            )
16394            .await?;
16395
16396            editor.update(cx, |editor, cx| {
16397                editor.refresh_document_highlights(cx);
16398            })?;
16399            Ok(())
16400        }))
16401    }
16402
16403    fn take_rename(
16404        &mut self,
16405        moving_cursor: bool,
16406        window: &mut Window,
16407        cx: &mut Context<Self>,
16408    ) -> Option<RenameState> {
16409        let rename = self.pending_rename.take()?;
16410        if rename.editor.focus_handle(cx).is_focused(window) {
16411            window.focus(&self.focus_handle);
16412        }
16413
16414        self.remove_blocks(
16415            [rename.block_id].into_iter().collect(),
16416            Some(Autoscroll::fit()),
16417            cx,
16418        );
16419        self.clear_highlights::<Rename>(cx);
16420        self.show_local_selections = true;
16421
16422        if moving_cursor {
16423            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16424                editor.selections.newest::<usize>(cx).head()
16425            });
16426
16427            // Update the selection to match the position of the selection inside
16428            // the rename editor.
16429            let snapshot = self.buffer.read(cx).read(cx);
16430            let rename_range = rename.range.to_offset(&snapshot);
16431            let cursor_in_editor = snapshot
16432                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16433                .min(rename_range.end);
16434            drop(snapshot);
16435
16436            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16437                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16438            });
16439        } else {
16440            self.refresh_document_highlights(cx);
16441        }
16442
16443        Some(rename)
16444    }
16445
16446    pub fn pending_rename(&self) -> Option<&RenameState> {
16447        self.pending_rename.as_ref()
16448    }
16449
16450    fn format(
16451        &mut self,
16452        _: &Format,
16453        window: &mut Window,
16454        cx: &mut Context<Self>,
16455    ) -> Option<Task<Result<()>>> {
16456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16457
16458        let project = match &self.project {
16459            Some(project) => project.clone(),
16460            None => return None,
16461        };
16462
16463        Some(self.perform_format(
16464            project,
16465            FormatTrigger::Manual,
16466            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16467            window,
16468            cx,
16469        ))
16470    }
16471
16472    fn format_selections(
16473        &mut self,
16474        _: &FormatSelections,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) -> Option<Task<Result<()>>> {
16478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16479
16480        let project = match &self.project {
16481            Some(project) => project.clone(),
16482            None => return None,
16483        };
16484
16485        let ranges = self
16486            .selections
16487            .all_adjusted(cx)
16488            .into_iter()
16489            .map(|selection| selection.range())
16490            .collect_vec();
16491
16492        Some(self.perform_format(
16493            project,
16494            FormatTrigger::Manual,
16495            FormatTarget::Ranges(ranges),
16496            window,
16497            cx,
16498        ))
16499    }
16500
16501    fn perform_format(
16502        &mut self,
16503        project: Entity<Project>,
16504        trigger: FormatTrigger,
16505        target: FormatTarget,
16506        window: &mut Window,
16507        cx: &mut Context<Self>,
16508    ) -> Task<Result<()>> {
16509        let buffer = self.buffer.clone();
16510        let (buffers, target) = match target {
16511            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16512            FormatTarget::Ranges(selection_ranges) => {
16513                let multi_buffer = buffer.read(cx);
16514                let snapshot = multi_buffer.read(cx);
16515                let mut buffers = HashSet::default();
16516                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16517                    BTreeMap::new();
16518                for selection_range in selection_ranges {
16519                    for (buffer, buffer_range, _) in
16520                        snapshot.range_to_buffer_ranges(selection_range)
16521                    {
16522                        let buffer_id = buffer.remote_id();
16523                        let start = buffer.anchor_before(buffer_range.start);
16524                        let end = buffer.anchor_after(buffer_range.end);
16525                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16526                        buffer_id_to_ranges
16527                            .entry(buffer_id)
16528                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16529                            .or_insert_with(|| vec![start..end]);
16530                    }
16531                }
16532                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16533            }
16534        };
16535
16536        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16537        let selections_prev = transaction_id_prev
16538            .and_then(|transaction_id_prev| {
16539                // default to selections as they were after the last edit, if we have them,
16540                // instead of how they are now.
16541                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16542                // will take you back to where you made the last edit, instead of staying where you scrolled
16543                self.selection_history
16544                    .transaction(transaction_id_prev)
16545                    .map(|t| t.0.clone())
16546            })
16547            .unwrap_or_else(|| self.selections.disjoint_anchors());
16548
16549        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16550        let format = project.update(cx, |project, cx| {
16551            project.format(buffers, target, true, trigger, cx)
16552        });
16553
16554        cx.spawn_in(window, async move |editor, cx| {
16555            let transaction = futures::select_biased! {
16556                transaction = format.log_err().fuse() => transaction,
16557                () = timeout => {
16558                    log::warn!("timed out waiting for formatting");
16559                    None
16560                }
16561            };
16562
16563            buffer
16564                .update(cx, |buffer, cx| {
16565                    if let Some(transaction) = transaction
16566                        && !buffer.is_singleton()
16567                    {
16568                        buffer.push_transaction(&transaction.0, cx);
16569                    }
16570                    cx.notify();
16571                })
16572                .ok();
16573
16574            if let Some(transaction_id_now) =
16575                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16576            {
16577                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16578                if has_new_transaction {
16579                    _ = editor.update(cx, |editor, _| {
16580                        editor
16581                            .selection_history
16582                            .insert_transaction(transaction_id_now, selections_prev);
16583                    });
16584                }
16585            }
16586
16587            Ok(())
16588        })
16589    }
16590
16591    fn organize_imports(
16592        &mut self,
16593        _: &OrganizeImports,
16594        window: &mut Window,
16595        cx: &mut Context<Self>,
16596    ) -> Option<Task<Result<()>>> {
16597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16598        let project = match &self.project {
16599            Some(project) => project.clone(),
16600            None => return None,
16601        };
16602        Some(self.perform_code_action_kind(
16603            project,
16604            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16605            window,
16606            cx,
16607        ))
16608    }
16609
16610    fn perform_code_action_kind(
16611        &mut self,
16612        project: Entity<Project>,
16613        kind: CodeActionKind,
16614        window: &mut Window,
16615        cx: &mut Context<Self>,
16616    ) -> Task<Result<()>> {
16617        let buffer = self.buffer.clone();
16618        let buffers = buffer.read(cx).all_buffers();
16619        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16620        let apply_action = project.update(cx, |project, cx| {
16621            project.apply_code_action_kind(buffers, kind, true, cx)
16622        });
16623        cx.spawn_in(window, async move |_, cx| {
16624            let transaction = futures::select_biased! {
16625                () = timeout => {
16626                    log::warn!("timed out waiting for executing code action");
16627                    None
16628                }
16629                transaction = apply_action.log_err().fuse() => transaction,
16630            };
16631            buffer
16632                .update(cx, |buffer, cx| {
16633                    // check if we need this
16634                    if let Some(transaction) = transaction
16635                        && !buffer.is_singleton()
16636                    {
16637                        buffer.push_transaction(&transaction.0, cx);
16638                    }
16639                    cx.notify();
16640                })
16641                .ok();
16642            Ok(())
16643        })
16644    }
16645
16646    pub fn restart_language_server(
16647        &mut self,
16648        _: &RestartLanguageServer,
16649        _: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) {
16652        if let Some(project) = self.project.clone() {
16653            self.buffer.update(cx, |multi_buffer, cx| {
16654                project.update(cx, |project, cx| {
16655                    project.restart_language_servers_for_buffers(
16656                        multi_buffer.all_buffers().into_iter().collect(),
16657                        HashSet::default(),
16658                        cx,
16659                    );
16660                });
16661            })
16662        }
16663    }
16664
16665    pub fn stop_language_server(
16666        &mut self,
16667        _: &StopLanguageServer,
16668        _: &mut Window,
16669        cx: &mut Context<Self>,
16670    ) {
16671        if let Some(project) = self.project.clone() {
16672            self.buffer.update(cx, |multi_buffer, cx| {
16673                project.update(cx, |project, cx| {
16674                    project.stop_language_servers_for_buffers(
16675                        multi_buffer.all_buffers().into_iter().collect(),
16676                        HashSet::default(),
16677                        cx,
16678                    );
16679                    cx.emit(project::Event::RefreshInlayHints);
16680                });
16681            });
16682        }
16683    }
16684
16685    fn cancel_language_server_work(
16686        workspace: &mut Workspace,
16687        _: &actions::CancelLanguageServerWork,
16688        _: &mut Window,
16689        cx: &mut Context<Workspace>,
16690    ) {
16691        let project = workspace.project();
16692        let buffers = workspace
16693            .active_item(cx)
16694            .and_then(|item| item.act_as::<Editor>(cx))
16695            .map_or(HashSet::default(), |editor| {
16696                editor.read(cx).buffer.read(cx).all_buffers()
16697            });
16698        project.update(cx, |project, cx| {
16699            project.cancel_language_server_work_for_buffers(buffers, cx);
16700        });
16701    }
16702
16703    fn show_character_palette(
16704        &mut self,
16705        _: &ShowCharacterPalette,
16706        window: &mut Window,
16707        _: &mut Context<Self>,
16708    ) {
16709        window.show_character_palette();
16710    }
16711
16712    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16713        if !self.diagnostics_enabled() {
16714            return;
16715        }
16716
16717        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16718            let buffer = self.buffer.read(cx).snapshot(cx);
16719            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16720            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16721            let is_valid = buffer
16722                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16723                .any(|entry| {
16724                    entry.diagnostic.is_primary
16725                        && !entry.range.is_empty()
16726                        && entry.range.start == primary_range_start
16727                        && entry.diagnostic.message == active_diagnostics.active_message
16728                });
16729
16730            if !is_valid {
16731                self.dismiss_diagnostics(cx);
16732            }
16733        }
16734    }
16735
16736    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16737        match &self.active_diagnostics {
16738            ActiveDiagnostic::Group(group) => Some(group),
16739            _ => None,
16740        }
16741    }
16742
16743    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16744        if !self.diagnostics_enabled() {
16745            return;
16746        }
16747        self.dismiss_diagnostics(cx);
16748        self.active_diagnostics = ActiveDiagnostic::All;
16749    }
16750
16751    fn activate_diagnostics(
16752        &mut self,
16753        buffer_id: BufferId,
16754        diagnostic: DiagnosticEntry<usize>,
16755        window: &mut Window,
16756        cx: &mut Context<Self>,
16757    ) {
16758        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16759            return;
16760        }
16761        self.dismiss_diagnostics(cx);
16762        let snapshot = self.snapshot(window, cx);
16763        let buffer = self.buffer.read(cx).snapshot(cx);
16764        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16765            return;
16766        };
16767
16768        let diagnostic_group = buffer
16769            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16770            .collect::<Vec<_>>();
16771
16772        let blocks =
16773            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16774
16775        let blocks = self.display_map.update(cx, |display_map, cx| {
16776            display_map.insert_blocks(blocks, cx).into_iter().collect()
16777        });
16778        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16779            active_range: buffer.anchor_before(diagnostic.range.start)
16780                ..buffer.anchor_after(diagnostic.range.end),
16781            active_message: diagnostic.diagnostic.message.clone(),
16782            group_id: diagnostic.diagnostic.group_id,
16783            blocks,
16784        });
16785        cx.notify();
16786    }
16787
16788    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16789        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16790            return;
16791        };
16792
16793        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16794        if let ActiveDiagnostic::Group(group) = prev {
16795            self.display_map.update(cx, |display_map, cx| {
16796                display_map.remove_blocks(group.blocks, cx);
16797            });
16798            cx.notify();
16799        }
16800    }
16801
16802    /// Disable inline diagnostics rendering for this editor.
16803    pub fn disable_inline_diagnostics(&mut self) {
16804        self.inline_diagnostics_enabled = false;
16805        self.inline_diagnostics_update = Task::ready(());
16806        self.inline_diagnostics.clear();
16807    }
16808
16809    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16810        self.diagnostics_enabled = false;
16811        self.dismiss_diagnostics(cx);
16812        self.inline_diagnostics_update = Task::ready(());
16813        self.inline_diagnostics.clear();
16814    }
16815
16816    pub fn diagnostics_enabled(&self) -> bool {
16817        self.diagnostics_enabled && self.mode.is_full()
16818    }
16819
16820    pub fn inline_diagnostics_enabled(&self) -> bool {
16821        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16822    }
16823
16824    pub fn show_inline_diagnostics(&self) -> bool {
16825        self.show_inline_diagnostics
16826    }
16827
16828    pub fn toggle_inline_diagnostics(
16829        &mut self,
16830        _: &ToggleInlineDiagnostics,
16831        window: &mut Window,
16832        cx: &mut Context<Editor>,
16833    ) {
16834        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16835        self.refresh_inline_diagnostics(false, window, cx);
16836    }
16837
16838    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16839        self.diagnostics_max_severity = severity;
16840        self.display_map.update(cx, |display_map, _| {
16841            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16842        });
16843    }
16844
16845    pub fn toggle_diagnostics(
16846        &mut self,
16847        _: &ToggleDiagnostics,
16848        window: &mut Window,
16849        cx: &mut Context<Editor>,
16850    ) {
16851        if !self.diagnostics_enabled() {
16852            return;
16853        }
16854
16855        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16856            EditorSettings::get_global(cx)
16857                .diagnostics_max_severity
16858                .filter(|severity| severity != &DiagnosticSeverity::Off)
16859                .unwrap_or(DiagnosticSeverity::Hint)
16860        } else {
16861            DiagnosticSeverity::Off
16862        };
16863        self.set_max_diagnostics_severity(new_severity, cx);
16864        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16865            self.active_diagnostics = ActiveDiagnostic::None;
16866            self.inline_diagnostics_update = Task::ready(());
16867            self.inline_diagnostics.clear();
16868        } else {
16869            self.refresh_inline_diagnostics(false, window, cx);
16870        }
16871
16872        cx.notify();
16873    }
16874
16875    pub fn toggle_minimap(
16876        &mut self,
16877        _: &ToggleMinimap,
16878        window: &mut Window,
16879        cx: &mut Context<Editor>,
16880    ) {
16881        if self.supports_minimap(cx) {
16882            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16883        }
16884    }
16885
16886    fn refresh_inline_diagnostics(
16887        &mut self,
16888        debounce: bool,
16889        window: &mut Window,
16890        cx: &mut Context<Self>,
16891    ) {
16892        let max_severity = ProjectSettings::get_global(cx)
16893            .diagnostics
16894            .inline
16895            .max_severity
16896            .unwrap_or(self.diagnostics_max_severity);
16897
16898        if !self.inline_diagnostics_enabled()
16899            || !self.show_inline_diagnostics
16900            || max_severity == DiagnosticSeverity::Off
16901        {
16902            self.inline_diagnostics_update = Task::ready(());
16903            self.inline_diagnostics.clear();
16904            return;
16905        }
16906
16907        let debounce_ms = ProjectSettings::get_global(cx)
16908            .diagnostics
16909            .inline
16910            .update_debounce_ms;
16911        let debounce = if debounce && debounce_ms > 0 {
16912            Some(Duration::from_millis(debounce_ms))
16913        } else {
16914            None
16915        };
16916        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16917            if let Some(debounce) = debounce {
16918                cx.background_executor().timer(debounce).await;
16919            }
16920            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16921                editor
16922                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16923                    .ok()
16924            }) else {
16925                return;
16926            };
16927
16928            let new_inline_diagnostics = cx
16929                .background_spawn(async move {
16930                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16931                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16932                        let message = diagnostic_entry
16933                            .diagnostic
16934                            .message
16935                            .split_once('\n')
16936                            .map(|(line, _)| line)
16937                            .map(SharedString::new)
16938                            .unwrap_or_else(|| {
16939                                SharedString::from(diagnostic_entry.diagnostic.message)
16940                            });
16941                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16942                        let (Ok(i) | Err(i)) = inline_diagnostics
16943                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16944                        inline_diagnostics.insert(
16945                            i,
16946                            (
16947                                start_anchor,
16948                                InlineDiagnostic {
16949                                    message,
16950                                    group_id: diagnostic_entry.diagnostic.group_id,
16951                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16952                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16953                                    severity: diagnostic_entry.diagnostic.severity,
16954                                },
16955                            ),
16956                        );
16957                    }
16958                    inline_diagnostics
16959                })
16960                .await;
16961
16962            editor
16963                .update(cx, |editor, cx| {
16964                    editor.inline_diagnostics = new_inline_diagnostics;
16965                    cx.notify();
16966                })
16967                .ok();
16968        });
16969    }
16970
16971    fn pull_diagnostics(
16972        &mut self,
16973        buffer_id: Option<BufferId>,
16974        window: &Window,
16975        cx: &mut Context<Self>,
16976    ) -> Option<()> {
16977        if !self.mode().is_full() {
16978            return None;
16979        }
16980        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16981            .diagnostics
16982            .lsp_pull_diagnostics;
16983        if !pull_diagnostics_settings.enabled {
16984            return None;
16985        }
16986        let project = self.project()?.downgrade();
16987        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16988        let mut buffers = self.buffer.read(cx).all_buffers();
16989        if let Some(buffer_id) = buffer_id {
16990            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16991        }
16992
16993        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16994            cx.background_executor().timer(debounce).await;
16995
16996            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16997                buffers
16998                    .into_iter()
16999                    .filter_map(|buffer| {
17000                        project
17001                            .update(cx, |project, cx| {
17002                                project.lsp_store().update(cx, |lsp_store, cx| {
17003                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17004                                })
17005                            })
17006                            .ok()
17007                    })
17008                    .collect::<FuturesUnordered<_>>()
17009            }) else {
17010                return;
17011            };
17012
17013            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17014                match pull_task {
17015                    Ok(()) => {
17016                        if editor
17017                            .update_in(cx, |editor, window, cx| {
17018                                editor.update_diagnostics_state(window, cx);
17019                            })
17020                            .is_err()
17021                        {
17022                            return;
17023                        }
17024                    }
17025                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17026                }
17027            }
17028        });
17029
17030        Some(())
17031    }
17032
17033    pub fn set_selections_from_remote(
17034        &mut self,
17035        selections: Vec<Selection<Anchor>>,
17036        pending_selection: Option<Selection<Anchor>>,
17037        window: &mut Window,
17038        cx: &mut Context<Self>,
17039    ) {
17040        let old_cursor_position = self.selections.newest_anchor().head();
17041        self.selections.change_with(cx, |s| {
17042            s.select_anchors(selections);
17043            if let Some(pending_selection) = pending_selection {
17044                s.set_pending(pending_selection, SelectMode::Character);
17045            } else {
17046                s.clear_pending();
17047            }
17048        });
17049        self.selections_did_change(
17050            false,
17051            &old_cursor_position,
17052            SelectionEffects::default(),
17053            window,
17054            cx,
17055        );
17056    }
17057
17058    pub fn transact(
17059        &mut self,
17060        window: &mut Window,
17061        cx: &mut Context<Self>,
17062        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17063    ) -> Option<TransactionId> {
17064        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17065            this.start_transaction_at(Instant::now(), window, cx);
17066            update(this, window, cx);
17067            this.end_transaction_at(Instant::now(), cx)
17068        })
17069    }
17070
17071    pub fn start_transaction_at(
17072        &mut self,
17073        now: Instant,
17074        window: &mut Window,
17075        cx: &mut Context<Self>,
17076    ) -> Option<TransactionId> {
17077        self.end_selection(window, cx);
17078        if let Some(tx_id) = self
17079            .buffer
17080            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17081        {
17082            self.selection_history
17083                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17084            cx.emit(EditorEvent::TransactionBegun {
17085                transaction_id: tx_id,
17086            });
17087            Some(tx_id)
17088        } else {
17089            None
17090        }
17091    }
17092
17093    pub fn end_transaction_at(
17094        &mut self,
17095        now: Instant,
17096        cx: &mut Context<Self>,
17097    ) -> Option<TransactionId> {
17098        if let Some(transaction_id) = self
17099            .buffer
17100            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17101        {
17102            if let Some((_, end_selections)) =
17103                self.selection_history.transaction_mut(transaction_id)
17104            {
17105                *end_selections = Some(self.selections.disjoint_anchors());
17106            } else {
17107                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17108            }
17109
17110            cx.emit(EditorEvent::Edited { transaction_id });
17111            Some(transaction_id)
17112        } else {
17113            None
17114        }
17115    }
17116
17117    pub fn modify_transaction_selection_history(
17118        &mut self,
17119        transaction_id: TransactionId,
17120        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17121    ) -> bool {
17122        self.selection_history
17123            .transaction_mut(transaction_id)
17124            .map(modify)
17125            .is_some()
17126    }
17127
17128    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17129        if self.selection_mark_mode {
17130            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17131                s.move_with(|_, sel| {
17132                    sel.collapse_to(sel.head(), SelectionGoal::None);
17133                });
17134            })
17135        }
17136        self.selection_mark_mode = true;
17137        cx.notify();
17138    }
17139
17140    pub fn swap_selection_ends(
17141        &mut self,
17142        _: &actions::SwapSelectionEnds,
17143        window: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) {
17146        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17147            s.move_with(|_, sel| {
17148                if sel.start != sel.end {
17149                    sel.reversed = !sel.reversed
17150                }
17151            });
17152        });
17153        self.request_autoscroll(Autoscroll::newest(), cx);
17154        cx.notify();
17155    }
17156
17157    pub fn toggle_focus(
17158        workspace: &mut Workspace,
17159        _: &actions::ToggleFocus,
17160        window: &mut Window,
17161        cx: &mut Context<Workspace>,
17162    ) {
17163        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17164            return;
17165        };
17166        workspace.activate_item(&item, true, true, window, cx);
17167    }
17168
17169    pub fn toggle_fold(
17170        &mut self,
17171        _: &actions::ToggleFold,
17172        window: &mut Window,
17173        cx: &mut Context<Self>,
17174    ) {
17175        if self.is_singleton(cx) {
17176            let selection = self.selections.newest::<Point>(cx);
17177
17178            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17179            let range = if selection.is_empty() {
17180                let point = selection.head().to_display_point(&display_map);
17181                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17182                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17183                    .to_point(&display_map);
17184                start..end
17185            } else {
17186                selection.range()
17187            };
17188            if display_map.folds_in_range(range).next().is_some() {
17189                self.unfold_lines(&Default::default(), window, cx)
17190            } else {
17191                self.fold(&Default::default(), window, cx)
17192            }
17193        } else {
17194            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17195            let buffer_ids: HashSet<_> = self
17196                .selections
17197                .disjoint_anchor_ranges()
17198                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17199                .collect();
17200
17201            let should_unfold = buffer_ids
17202                .iter()
17203                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17204
17205            for buffer_id in buffer_ids {
17206                if should_unfold {
17207                    self.unfold_buffer(buffer_id, cx);
17208                } else {
17209                    self.fold_buffer(buffer_id, cx);
17210                }
17211            }
17212        }
17213    }
17214
17215    pub fn toggle_fold_recursive(
17216        &mut self,
17217        _: &actions::ToggleFoldRecursive,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) {
17221        let selection = self.selections.newest::<Point>(cx);
17222
17223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17224        let range = if selection.is_empty() {
17225            let point = selection.head().to_display_point(&display_map);
17226            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17227            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17228                .to_point(&display_map);
17229            start..end
17230        } else {
17231            selection.range()
17232        };
17233        if display_map.folds_in_range(range).next().is_some() {
17234            self.unfold_recursive(&Default::default(), window, cx)
17235        } else {
17236            self.fold_recursive(&Default::default(), window, cx)
17237        }
17238    }
17239
17240    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17241        if self.is_singleton(cx) {
17242            let mut to_fold = Vec::new();
17243            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17244            let selections = self.selections.all_adjusted(cx);
17245
17246            for selection in selections {
17247                let range = selection.range().sorted();
17248                let buffer_start_row = range.start.row;
17249
17250                if range.start.row != range.end.row {
17251                    let mut found = false;
17252                    let mut row = range.start.row;
17253                    while row <= range.end.row {
17254                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17255                        {
17256                            found = true;
17257                            row = crease.range().end.row + 1;
17258                            to_fold.push(crease);
17259                        } else {
17260                            row += 1
17261                        }
17262                    }
17263                    if found {
17264                        continue;
17265                    }
17266                }
17267
17268                for row in (0..=range.start.row).rev() {
17269                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17270                        && crease.range().end.row >= buffer_start_row
17271                    {
17272                        to_fold.push(crease);
17273                        if row <= range.start.row {
17274                            break;
17275                        }
17276                    }
17277                }
17278            }
17279
17280            self.fold_creases(to_fold, true, window, cx);
17281        } else {
17282            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17283            let buffer_ids = self
17284                .selections
17285                .disjoint_anchor_ranges()
17286                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17287                .collect::<HashSet<_>>();
17288            for buffer_id in buffer_ids {
17289                self.fold_buffer(buffer_id, cx);
17290            }
17291        }
17292    }
17293
17294    pub fn toggle_fold_all(
17295        &mut self,
17296        _: &actions::ToggleFoldAll,
17297        window: &mut Window,
17298        cx: &mut Context<Self>,
17299    ) {
17300        if self.buffer.read(cx).is_singleton() {
17301            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17302            let has_folds = display_map
17303                .folds_in_range(0..display_map.buffer_snapshot.len())
17304                .next()
17305                .is_some();
17306
17307            if has_folds {
17308                self.unfold_all(&actions::UnfoldAll, window, cx);
17309            } else {
17310                self.fold_all(&actions::FoldAll, window, cx);
17311            }
17312        } else {
17313            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17314            let should_unfold = buffer_ids
17315                .iter()
17316                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17317
17318            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17319                editor
17320                    .update_in(cx, |editor, _, cx| {
17321                        for buffer_id in buffer_ids {
17322                            if should_unfold {
17323                                editor.unfold_buffer(buffer_id, cx);
17324                            } else {
17325                                editor.fold_buffer(buffer_id, cx);
17326                            }
17327                        }
17328                    })
17329                    .ok();
17330            });
17331        }
17332    }
17333
17334    fn fold_at_level(
17335        &mut self,
17336        fold_at: &FoldAtLevel,
17337        window: &mut Window,
17338        cx: &mut Context<Self>,
17339    ) {
17340        if !self.buffer.read(cx).is_singleton() {
17341            return;
17342        }
17343
17344        let fold_at_level = fold_at.0;
17345        let snapshot = self.buffer.read(cx).snapshot(cx);
17346        let mut to_fold = Vec::new();
17347        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17348
17349        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17350            while start_row < end_row {
17351                match self
17352                    .snapshot(window, cx)
17353                    .crease_for_buffer_row(MultiBufferRow(start_row))
17354                {
17355                    Some(crease) => {
17356                        let nested_start_row = crease.range().start.row + 1;
17357                        let nested_end_row = crease.range().end.row;
17358
17359                        if current_level < fold_at_level {
17360                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17361                        } else if current_level == fold_at_level {
17362                            to_fold.push(crease);
17363                        }
17364
17365                        start_row = nested_end_row + 1;
17366                    }
17367                    None => start_row += 1,
17368                }
17369            }
17370        }
17371
17372        self.fold_creases(to_fold, true, window, cx);
17373    }
17374
17375    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17376        if self.buffer.read(cx).is_singleton() {
17377            let mut fold_ranges = Vec::new();
17378            let snapshot = self.buffer.read(cx).snapshot(cx);
17379
17380            for row in 0..snapshot.max_row().0 {
17381                if let Some(foldable_range) = self
17382                    .snapshot(window, cx)
17383                    .crease_for_buffer_row(MultiBufferRow(row))
17384                {
17385                    fold_ranges.push(foldable_range);
17386                }
17387            }
17388
17389            self.fold_creases(fold_ranges, true, window, cx);
17390        } else {
17391            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17392                editor
17393                    .update_in(cx, |editor, _, cx| {
17394                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17395                            editor.fold_buffer(buffer_id, cx);
17396                        }
17397                    })
17398                    .ok();
17399            });
17400        }
17401    }
17402
17403    pub fn fold_function_bodies(
17404        &mut self,
17405        _: &actions::FoldFunctionBodies,
17406        window: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        let snapshot = self.buffer.read(cx).snapshot(cx);
17410
17411        let ranges = snapshot
17412            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17413            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17414            .collect::<Vec<_>>();
17415
17416        let creases = ranges
17417            .into_iter()
17418            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17419            .collect();
17420
17421        self.fold_creases(creases, true, window, cx);
17422    }
17423
17424    pub fn fold_recursive(
17425        &mut self,
17426        _: &actions::FoldRecursive,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        let mut to_fold = Vec::new();
17431        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17432        let selections = self.selections.all_adjusted(cx);
17433
17434        for selection in selections {
17435            let range = selection.range().sorted();
17436            let buffer_start_row = range.start.row;
17437
17438            if range.start.row != range.end.row {
17439                let mut found = false;
17440                for row in range.start.row..=range.end.row {
17441                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17442                        found = true;
17443                        to_fold.push(crease);
17444                    }
17445                }
17446                if found {
17447                    continue;
17448                }
17449            }
17450
17451            for row in (0..=range.start.row).rev() {
17452                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17453                    if crease.range().end.row >= buffer_start_row {
17454                        to_fold.push(crease);
17455                    } else {
17456                        break;
17457                    }
17458                }
17459            }
17460        }
17461
17462        self.fold_creases(to_fold, true, window, cx);
17463    }
17464
17465    pub fn fold_at(
17466        &mut self,
17467        buffer_row: MultiBufferRow,
17468        window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17472
17473        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17474            let autoscroll = self
17475                .selections
17476                .all::<Point>(cx)
17477                .iter()
17478                .any(|selection| crease.range().overlaps(&selection.range()));
17479
17480            self.fold_creases(vec![crease], autoscroll, window, cx);
17481        }
17482    }
17483
17484    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17485        if self.is_singleton(cx) {
17486            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17487            let buffer = &display_map.buffer_snapshot;
17488            let selections = self.selections.all::<Point>(cx);
17489            let ranges = selections
17490                .iter()
17491                .map(|s| {
17492                    let range = s.display_range(&display_map).sorted();
17493                    let mut start = range.start.to_point(&display_map);
17494                    let mut end = range.end.to_point(&display_map);
17495                    start.column = 0;
17496                    end.column = buffer.line_len(MultiBufferRow(end.row));
17497                    start..end
17498                })
17499                .collect::<Vec<_>>();
17500
17501            self.unfold_ranges(&ranges, true, true, cx);
17502        } else {
17503            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17504            let buffer_ids = self
17505                .selections
17506                .disjoint_anchor_ranges()
17507                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17508                .collect::<HashSet<_>>();
17509            for buffer_id in buffer_ids {
17510                self.unfold_buffer(buffer_id, cx);
17511            }
17512        }
17513    }
17514
17515    pub fn unfold_recursive(
17516        &mut self,
17517        _: &UnfoldRecursive,
17518        _window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) {
17521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17522        let selections = self.selections.all::<Point>(cx);
17523        let ranges = selections
17524            .iter()
17525            .map(|s| {
17526                let mut range = s.display_range(&display_map).sorted();
17527                *range.start.column_mut() = 0;
17528                *range.end.column_mut() = display_map.line_len(range.end.row());
17529                let start = range.start.to_point(&display_map);
17530                let end = range.end.to_point(&display_map);
17531                start..end
17532            })
17533            .collect::<Vec<_>>();
17534
17535        self.unfold_ranges(&ranges, true, true, cx);
17536    }
17537
17538    pub fn unfold_at(
17539        &mut self,
17540        buffer_row: MultiBufferRow,
17541        _window: &mut Window,
17542        cx: &mut Context<Self>,
17543    ) {
17544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17545
17546        let intersection_range = Point::new(buffer_row.0, 0)
17547            ..Point::new(
17548                buffer_row.0,
17549                display_map.buffer_snapshot.line_len(buffer_row),
17550            );
17551
17552        let autoscroll = self
17553            .selections
17554            .all::<Point>(cx)
17555            .iter()
17556            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17557
17558        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17559    }
17560
17561    pub fn unfold_all(
17562        &mut self,
17563        _: &actions::UnfoldAll,
17564        _window: &mut Window,
17565        cx: &mut Context<Self>,
17566    ) {
17567        if self.buffer.read(cx).is_singleton() {
17568            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17569            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17570        } else {
17571            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17572                editor
17573                    .update(cx, |editor, cx| {
17574                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17575                            editor.unfold_buffer(buffer_id, cx);
17576                        }
17577                    })
17578                    .ok();
17579            });
17580        }
17581    }
17582
17583    pub fn fold_selected_ranges(
17584        &mut self,
17585        _: &FoldSelectedRanges,
17586        window: &mut Window,
17587        cx: &mut Context<Self>,
17588    ) {
17589        let selections = self.selections.all_adjusted(cx);
17590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17591        let ranges = selections
17592            .into_iter()
17593            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17594            .collect::<Vec<_>>();
17595        self.fold_creases(ranges, true, window, cx);
17596    }
17597
17598    pub fn fold_ranges<T: ToOffset + Clone>(
17599        &mut self,
17600        ranges: Vec<Range<T>>,
17601        auto_scroll: bool,
17602        window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17606        let ranges = ranges
17607            .into_iter()
17608            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17609            .collect::<Vec<_>>();
17610        self.fold_creases(ranges, auto_scroll, window, cx);
17611    }
17612
17613    pub fn fold_creases<T: ToOffset + Clone>(
17614        &mut self,
17615        creases: Vec<Crease<T>>,
17616        auto_scroll: bool,
17617        _window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        if creases.is_empty() {
17621            return;
17622        }
17623
17624        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17625
17626        if auto_scroll {
17627            self.request_autoscroll(Autoscroll::fit(), cx);
17628        }
17629
17630        cx.notify();
17631
17632        self.scrollbar_marker_state.dirty = true;
17633        self.folds_did_change(cx);
17634    }
17635
17636    /// Removes any folds whose ranges intersect any of the given ranges.
17637    pub fn unfold_ranges<T: ToOffset + Clone>(
17638        &mut self,
17639        ranges: &[Range<T>],
17640        inclusive: bool,
17641        auto_scroll: bool,
17642        cx: &mut Context<Self>,
17643    ) {
17644        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17645            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17646        });
17647        self.folds_did_change(cx);
17648    }
17649
17650    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17651        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17652            return;
17653        }
17654        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17655        self.display_map.update(cx, |display_map, cx| {
17656            display_map.fold_buffers([buffer_id], cx)
17657        });
17658        cx.emit(EditorEvent::BufferFoldToggled {
17659            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17660            folded: true,
17661        });
17662        cx.notify();
17663    }
17664
17665    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17666        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17667            return;
17668        }
17669        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17670        self.display_map.update(cx, |display_map, cx| {
17671            display_map.unfold_buffers([buffer_id], cx);
17672        });
17673        cx.emit(EditorEvent::BufferFoldToggled {
17674            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17675            folded: false,
17676        });
17677        cx.notify();
17678    }
17679
17680    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17681        self.display_map.read(cx).is_buffer_folded(buffer)
17682    }
17683
17684    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17685        self.display_map.read(cx).folded_buffers()
17686    }
17687
17688    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17689        self.display_map.update(cx, |display_map, cx| {
17690            display_map.disable_header_for_buffer(buffer_id, cx);
17691        });
17692        cx.notify();
17693    }
17694
17695    /// Removes any folds with the given ranges.
17696    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17697        &mut self,
17698        ranges: &[Range<T>],
17699        type_id: TypeId,
17700        auto_scroll: bool,
17701        cx: &mut Context<Self>,
17702    ) {
17703        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17704            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17705        });
17706        self.folds_did_change(cx);
17707    }
17708
17709    fn remove_folds_with<T: ToOffset + Clone>(
17710        &mut self,
17711        ranges: &[Range<T>],
17712        auto_scroll: bool,
17713        cx: &mut Context<Self>,
17714        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17715    ) {
17716        if ranges.is_empty() {
17717            return;
17718        }
17719
17720        let mut buffers_affected = HashSet::default();
17721        let multi_buffer = self.buffer().read(cx);
17722        for range in ranges {
17723            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17724                buffers_affected.insert(buffer.read(cx).remote_id());
17725            };
17726        }
17727
17728        self.display_map.update(cx, update);
17729
17730        if auto_scroll {
17731            self.request_autoscroll(Autoscroll::fit(), cx);
17732        }
17733
17734        cx.notify();
17735        self.scrollbar_marker_state.dirty = true;
17736        self.active_indent_guides_state.dirty = true;
17737    }
17738
17739    pub fn update_renderer_widths(
17740        &mut self,
17741        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17742        cx: &mut Context<Self>,
17743    ) -> bool {
17744        self.display_map
17745            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17746    }
17747
17748    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17749        self.display_map.read(cx).fold_placeholder.clone()
17750    }
17751
17752    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17753        self.buffer.update(cx, |buffer, cx| {
17754            buffer.set_all_diff_hunks_expanded(cx);
17755        });
17756    }
17757
17758    pub fn expand_all_diff_hunks(
17759        &mut self,
17760        _: &ExpandAllDiffHunks,
17761        _window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        self.buffer.update(cx, |buffer, cx| {
17765            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17766        });
17767    }
17768
17769    pub fn toggle_selected_diff_hunks(
17770        &mut self,
17771        _: &ToggleSelectedDiffHunks,
17772        _window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17776        self.toggle_diff_hunks_in_ranges(ranges, cx);
17777    }
17778
17779    pub fn diff_hunks_in_ranges<'a>(
17780        &'a self,
17781        ranges: &'a [Range<Anchor>],
17782        buffer: &'a MultiBufferSnapshot,
17783    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17784        ranges.iter().flat_map(move |range| {
17785            let end_excerpt_id = range.end.excerpt_id;
17786            let range = range.to_point(buffer);
17787            let mut peek_end = range.end;
17788            if range.end.row < buffer.max_row().0 {
17789                peek_end = Point::new(range.end.row + 1, 0);
17790            }
17791            buffer
17792                .diff_hunks_in_range(range.start..peek_end)
17793                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17794        })
17795    }
17796
17797    pub fn has_stageable_diff_hunks_in_ranges(
17798        &self,
17799        ranges: &[Range<Anchor>],
17800        snapshot: &MultiBufferSnapshot,
17801    ) -> bool {
17802        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17803        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17804    }
17805
17806    pub fn toggle_staged_selected_diff_hunks(
17807        &mut self,
17808        _: &::git::ToggleStaged,
17809        _: &mut Window,
17810        cx: &mut Context<Self>,
17811    ) {
17812        let snapshot = self.buffer.read(cx).snapshot(cx);
17813        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17814        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17815        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17816    }
17817
17818    pub fn set_render_diff_hunk_controls(
17819        &mut self,
17820        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17821        cx: &mut Context<Self>,
17822    ) {
17823        self.render_diff_hunk_controls = render_diff_hunk_controls;
17824        cx.notify();
17825    }
17826
17827    pub fn stage_and_next(
17828        &mut self,
17829        _: &::git::StageAndNext,
17830        window: &mut Window,
17831        cx: &mut Context<Self>,
17832    ) {
17833        self.do_stage_or_unstage_and_next(true, window, cx);
17834    }
17835
17836    pub fn unstage_and_next(
17837        &mut self,
17838        _: &::git::UnstageAndNext,
17839        window: &mut Window,
17840        cx: &mut Context<Self>,
17841    ) {
17842        self.do_stage_or_unstage_and_next(false, window, cx);
17843    }
17844
17845    pub fn stage_or_unstage_diff_hunks(
17846        &mut self,
17847        stage: bool,
17848        ranges: Vec<Range<Anchor>>,
17849        cx: &mut Context<Self>,
17850    ) {
17851        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17852        cx.spawn(async move |this, cx| {
17853            task.await?;
17854            this.update(cx, |this, cx| {
17855                let snapshot = this.buffer.read(cx).snapshot(cx);
17856                let chunk_by = this
17857                    .diff_hunks_in_ranges(&ranges, &snapshot)
17858                    .chunk_by(|hunk| hunk.buffer_id);
17859                for (buffer_id, hunks) in &chunk_by {
17860                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17861                }
17862            })
17863        })
17864        .detach_and_log_err(cx);
17865    }
17866
17867    fn save_buffers_for_ranges_if_needed(
17868        &mut self,
17869        ranges: &[Range<Anchor>],
17870        cx: &mut Context<Editor>,
17871    ) -> Task<Result<()>> {
17872        let multibuffer = self.buffer.read(cx);
17873        let snapshot = multibuffer.read(cx);
17874        let buffer_ids: HashSet<_> = ranges
17875            .iter()
17876            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17877            .collect();
17878        drop(snapshot);
17879
17880        let mut buffers = HashSet::default();
17881        for buffer_id in buffer_ids {
17882            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17883                let buffer = buffer_entity.read(cx);
17884                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17885                {
17886                    buffers.insert(buffer_entity);
17887                }
17888            }
17889        }
17890
17891        if let Some(project) = &self.project {
17892            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17893        } else {
17894            Task::ready(Ok(()))
17895        }
17896    }
17897
17898    fn do_stage_or_unstage_and_next(
17899        &mut self,
17900        stage: bool,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17905
17906        if ranges.iter().any(|range| range.start != range.end) {
17907            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17908            return;
17909        }
17910
17911        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17912        let snapshot = self.snapshot(window, cx);
17913        let position = self.selections.newest::<Point>(cx).head();
17914        let mut row = snapshot
17915            .buffer_snapshot
17916            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17917            .find(|hunk| hunk.row_range.start.0 > position.row)
17918            .map(|hunk| hunk.row_range.start);
17919
17920        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17921        // Outside of the project diff editor, wrap around to the beginning.
17922        if !all_diff_hunks_expanded {
17923            row = row.or_else(|| {
17924                snapshot
17925                    .buffer_snapshot
17926                    .diff_hunks_in_range(Point::zero()..position)
17927                    .find(|hunk| hunk.row_range.end.0 < position.row)
17928                    .map(|hunk| hunk.row_range.start)
17929            });
17930        }
17931
17932        if let Some(row) = row {
17933            let destination = Point::new(row.0, 0);
17934            let autoscroll = Autoscroll::center();
17935
17936            self.unfold_ranges(&[destination..destination], false, false, cx);
17937            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17938                s.select_ranges([destination..destination]);
17939            });
17940        }
17941    }
17942
17943    fn do_stage_or_unstage(
17944        &self,
17945        stage: bool,
17946        buffer_id: BufferId,
17947        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17948        cx: &mut App,
17949    ) -> Option<()> {
17950        let project = self.project()?;
17951        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17952        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17953        let buffer_snapshot = buffer.read(cx).snapshot();
17954        let file_exists = buffer_snapshot
17955            .file()
17956            .is_some_and(|file| file.disk_state().exists());
17957        diff.update(cx, |diff, cx| {
17958            diff.stage_or_unstage_hunks(
17959                stage,
17960                &hunks
17961                    .map(|hunk| buffer_diff::DiffHunk {
17962                        buffer_range: hunk.buffer_range,
17963                        diff_base_byte_range: hunk.diff_base_byte_range,
17964                        secondary_status: hunk.secondary_status,
17965                        range: Point::zero()..Point::zero(), // unused
17966                    })
17967                    .collect::<Vec<_>>(),
17968                &buffer_snapshot,
17969                file_exists,
17970                cx,
17971            )
17972        });
17973        None
17974    }
17975
17976    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17977        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17978        self.buffer
17979            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17980    }
17981
17982    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17983        self.buffer.update(cx, |buffer, cx| {
17984            let ranges = vec![Anchor::min()..Anchor::max()];
17985            if !buffer.all_diff_hunks_expanded()
17986                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17987            {
17988                buffer.collapse_diff_hunks(ranges, cx);
17989                true
17990            } else {
17991                false
17992            }
17993        })
17994    }
17995
17996    fn toggle_diff_hunks_in_ranges(
17997        &mut self,
17998        ranges: Vec<Range<Anchor>>,
17999        cx: &mut Context<Editor>,
18000    ) {
18001        self.buffer.update(cx, |buffer, cx| {
18002            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18003            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18004        })
18005    }
18006
18007    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18008        self.buffer.update(cx, |buffer, cx| {
18009            let snapshot = buffer.snapshot(cx);
18010            let excerpt_id = range.end.excerpt_id;
18011            let point_range = range.to_point(&snapshot);
18012            let expand = !buffer.single_hunk_is_expanded(range, cx);
18013            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18014        })
18015    }
18016
18017    pub(crate) fn apply_all_diff_hunks(
18018        &mut self,
18019        _: &ApplyAllDiffHunks,
18020        window: &mut Window,
18021        cx: &mut Context<Self>,
18022    ) {
18023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18024
18025        let buffers = self.buffer.read(cx).all_buffers();
18026        for branch_buffer in buffers {
18027            branch_buffer.update(cx, |branch_buffer, cx| {
18028                branch_buffer.merge_into_base(Vec::new(), cx);
18029            });
18030        }
18031
18032        if let Some(project) = self.project.clone() {
18033            self.save(
18034                SaveOptions {
18035                    format: true,
18036                    autosave: false,
18037                },
18038                project,
18039                window,
18040                cx,
18041            )
18042            .detach_and_log_err(cx);
18043        }
18044    }
18045
18046    pub(crate) fn apply_selected_diff_hunks(
18047        &mut self,
18048        _: &ApplyDiffHunk,
18049        window: &mut Window,
18050        cx: &mut Context<Self>,
18051    ) {
18052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18053        let snapshot = self.snapshot(window, cx);
18054        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18055        let mut ranges_by_buffer = HashMap::default();
18056        self.transact(window, cx, |editor, _window, cx| {
18057            for hunk in hunks {
18058                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18059                    ranges_by_buffer
18060                        .entry(buffer.clone())
18061                        .or_insert_with(Vec::new)
18062                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18063                }
18064            }
18065
18066            for (buffer, ranges) in ranges_by_buffer {
18067                buffer.update(cx, |buffer, cx| {
18068                    buffer.merge_into_base(ranges, cx);
18069                });
18070            }
18071        });
18072
18073        if let Some(project) = self.project.clone() {
18074            self.save(
18075                SaveOptions {
18076                    format: true,
18077                    autosave: false,
18078                },
18079                project,
18080                window,
18081                cx,
18082            )
18083            .detach_and_log_err(cx);
18084        }
18085    }
18086
18087    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18088        if hovered != self.gutter_hovered {
18089            self.gutter_hovered = hovered;
18090            cx.notify();
18091        }
18092    }
18093
18094    pub fn insert_blocks(
18095        &mut self,
18096        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18097        autoscroll: Option<Autoscroll>,
18098        cx: &mut Context<Self>,
18099    ) -> Vec<CustomBlockId> {
18100        let blocks = self
18101            .display_map
18102            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18103        if let Some(autoscroll) = autoscroll {
18104            self.request_autoscroll(autoscroll, cx);
18105        }
18106        cx.notify();
18107        blocks
18108    }
18109
18110    pub fn resize_blocks(
18111        &mut self,
18112        heights: HashMap<CustomBlockId, u32>,
18113        autoscroll: Option<Autoscroll>,
18114        cx: &mut Context<Self>,
18115    ) {
18116        self.display_map
18117            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18118        if let Some(autoscroll) = autoscroll {
18119            self.request_autoscroll(autoscroll, cx);
18120        }
18121        cx.notify();
18122    }
18123
18124    pub fn replace_blocks(
18125        &mut self,
18126        renderers: HashMap<CustomBlockId, RenderBlock>,
18127        autoscroll: Option<Autoscroll>,
18128        cx: &mut Context<Self>,
18129    ) {
18130        self.display_map
18131            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18132        if let Some(autoscroll) = autoscroll {
18133            self.request_autoscroll(autoscroll, cx);
18134        }
18135        cx.notify();
18136    }
18137
18138    pub fn remove_blocks(
18139        &mut self,
18140        block_ids: HashSet<CustomBlockId>,
18141        autoscroll: Option<Autoscroll>,
18142        cx: &mut Context<Self>,
18143    ) {
18144        self.display_map.update(cx, |display_map, cx| {
18145            display_map.remove_blocks(block_ids, cx)
18146        });
18147        if let Some(autoscroll) = autoscroll {
18148            self.request_autoscroll(autoscroll, cx);
18149        }
18150        cx.notify();
18151    }
18152
18153    pub fn row_for_block(
18154        &self,
18155        block_id: CustomBlockId,
18156        cx: &mut Context<Self>,
18157    ) -> Option<DisplayRow> {
18158        self.display_map
18159            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18160    }
18161
18162    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18163        self.focused_block = Some(focused_block);
18164    }
18165
18166    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18167        self.focused_block.take()
18168    }
18169
18170    pub fn insert_creases(
18171        &mut self,
18172        creases: impl IntoIterator<Item = Crease<Anchor>>,
18173        cx: &mut Context<Self>,
18174    ) -> Vec<CreaseId> {
18175        self.display_map
18176            .update(cx, |map, cx| map.insert_creases(creases, cx))
18177    }
18178
18179    pub fn remove_creases(
18180        &mut self,
18181        ids: impl IntoIterator<Item = CreaseId>,
18182        cx: &mut Context<Self>,
18183    ) -> Vec<(CreaseId, Range<Anchor>)> {
18184        self.display_map
18185            .update(cx, |map, cx| map.remove_creases(ids, cx))
18186    }
18187
18188    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18189        self.display_map
18190            .update(cx, |map, cx| map.snapshot(cx))
18191            .longest_row()
18192    }
18193
18194    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18195        self.display_map
18196            .update(cx, |map, cx| map.snapshot(cx))
18197            .max_point()
18198    }
18199
18200    pub fn text(&self, cx: &App) -> String {
18201        self.buffer.read(cx).read(cx).text()
18202    }
18203
18204    pub fn is_empty(&self, cx: &App) -> bool {
18205        self.buffer.read(cx).read(cx).is_empty()
18206    }
18207
18208    pub fn text_option(&self, cx: &App) -> Option<String> {
18209        let text = self.text(cx);
18210        let text = text.trim();
18211
18212        if text.is_empty() {
18213            return None;
18214        }
18215
18216        Some(text.to_string())
18217    }
18218
18219    pub fn set_text(
18220        &mut self,
18221        text: impl Into<Arc<str>>,
18222        window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) {
18225        self.transact(window, cx, |this, _, cx| {
18226            this.buffer
18227                .read(cx)
18228                .as_singleton()
18229                .expect("you can only call set_text on editors for singleton buffers")
18230                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18231        });
18232    }
18233
18234    pub fn display_text(&self, cx: &mut App) -> String {
18235        self.display_map
18236            .update(cx, |map, cx| map.snapshot(cx))
18237            .text()
18238    }
18239
18240    fn create_minimap(
18241        &self,
18242        minimap_settings: MinimapSettings,
18243        window: &mut Window,
18244        cx: &mut Context<Self>,
18245    ) -> Option<Entity<Self>> {
18246        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18247            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18248    }
18249
18250    fn initialize_new_minimap(
18251        &self,
18252        minimap_settings: MinimapSettings,
18253        window: &mut Window,
18254        cx: &mut Context<Self>,
18255    ) -> Entity<Self> {
18256        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18257
18258        let mut minimap = Editor::new_internal(
18259            EditorMode::Minimap {
18260                parent: cx.weak_entity(),
18261            },
18262            self.buffer.clone(),
18263            None,
18264            Some(self.display_map.clone()),
18265            window,
18266            cx,
18267        );
18268        minimap.scroll_manager.clone_state(&self.scroll_manager);
18269        minimap.set_text_style_refinement(TextStyleRefinement {
18270            font_size: Some(MINIMAP_FONT_SIZE),
18271            font_weight: Some(MINIMAP_FONT_WEIGHT),
18272            ..Default::default()
18273        });
18274        minimap.update_minimap_configuration(minimap_settings, cx);
18275        cx.new(|_| minimap)
18276    }
18277
18278    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18279        let current_line_highlight = minimap_settings
18280            .current_line_highlight
18281            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18282        self.set_current_line_highlight(Some(current_line_highlight));
18283    }
18284
18285    pub fn minimap(&self) -> Option<&Entity<Self>> {
18286        self.minimap
18287            .as_ref()
18288            .filter(|_| self.minimap_visibility.visible())
18289    }
18290
18291    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18292        let mut wrap_guides = smallvec![];
18293
18294        if self.show_wrap_guides == Some(false) {
18295            return wrap_guides;
18296        }
18297
18298        let settings = self.buffer.read(cx).language_settings(cx);
18299        if settings.show_wrap_guides {
18300            match self.soft_wrap_mode(cx) {
18301                SoftWrap::Column(soft_wrap) => {
18302                    wrap_guides.push((soft_wrap as usize, true));
18303                }
18304                SoftWrap::Bounded(soft_wrap) => {
18305                    wrap_guides.push((soft_wrap as usize, true));
18306                }
18307                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18308            }
18309            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18310        }
18311
18312        wrap_guides
18313    }
18314
18315    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18316        let settings = self.buffer.read(cx).language_settings(cx);
18317        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18318        match mode {
18319            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18320                SoftWrap::None
18321            }
18322            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18323            language_settings::SoftWrap::PreferredLineLength => {
18324                SoftWrap::Column(settings.preferred_line_length)
18325            }
18326            language_settings::SoftWrap::Bounded => {
18327                SoftWrap::Bounded(settings.preferred_line_length)
18328            }
18329        }
18330    }
18331
18332    pub fn set_soft_wrap_mode(
18333        &mut self,
18334        mode: language_settings::SoftWrap,
18335
18336        cx: &mut Context<Self>,
18337    ) {
18338        self.soft_wrap_mode_override = Some(mode);
18339        cx.notify();
18340    }
18341
18342    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18343        self.hard_wrap = hard_wrap;
18344        cx.notify();
18345    }
18346
18347    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18348        self.text_style_refinement = Some(style);
18349    }
18350
18351    /// called by the Element so we know what style we were most recently rendered with.
18352    pub(crate) fn set_style(
18353        &mut self,
18354        style: EditorStyle,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        // We intentionally do not inform the display map about the minimap style
18359        // so that wrapping is not recalculated and stays consistent for the editor
18360        // and its linked minimap.
18361        if !self.mode.is_minimap() {
18362            let rem_size = window.rem_size();
18363            self.display_map.update(cx, |map, cx| {
18364                map.set_font(
18365                    style.text.font(),
18366                    style.text.font_size.to_pixels(rem_size),
18367                    cx,
18368                )
18369            });
18370        }
18371        self.style = Some(style);
18372    }
18373
18374    pub fn style(&self) -> Option<&EditorStyle> {
18375        self.style.as_ref()
18376    }
18377
18378    // Called by the element. This method is not designed to be called outside of the editor
18379    // element's layout code because it does not notify when rewrapping is computed synchronously.
18380    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18381        self.display_map
18382            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18383    }
18384
18385    pub fn set_soft_wrap(&mut self) {
18386        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18387    }
18388
18389    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18390        if self.soft_wrap_mode_override.is_some() {
18391            self.soft_wrap_mode_override.take();
18392        } else {
18393            let soft_wrap = match self.soft_wrap_mode(cx) {
18394                SoftWrap::GitDiff => return,
18395                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18396                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18397                    language_settings::SoftWrap::None
18398                }
18399            };
18400            self.soft_wrap_mode_override = Some(soft_wrap);
18401        }
18402        cx.notify();
18403    }
18404
18405    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18406        let Some(workspace) = self.workspace() else {
18407            return;
18408        };
18409        let fs = workspace.read(cx).app_state().fs.clone();
18410        let current_show = TabBarSettings::get_global(cx).show;
18411        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18412            setting.show = Some(!current_show);
18413        });
18414    }
18415
18416    pub fn toggle_indent_guides(
18417        &mut self,
18418        _: &ToggleIndentGuides,
18419        _: &mut Window,
18420        cx: &mut Context<Self>,
18421    ) {
18422        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18423            self.buffer
18424                .read(cx)
18425                .language_settings(cx)
18426                .indent_guides
18427                .enabled
18428        });
18429        self.show_indent_guides = Some(!currently_enabled);
18430        cx.notify();
18431    }
18432
18433    fn should_show_indent_guides(&self) -> Option<bool> {
18434        self.show_indent_guides
18435    }
18436
18437    pub fn toggle_line_numbers(
18438        &mut self,
18439        _: &ToggleLineNumbers,
18440        _: &mut Window,
18441        cx: &mut Context<Self>,
18442    ) {
18443        let mut editor_settings = EditorSettings::get_global(cx).clone();
18444        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18445        EditorSettings::override_global(editor_settings, cx);
18446    }
18447
18448    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18449        if let Some(show_line_numbers) = self.show_line_numbers {
18450            return show_line_numbers;
18451        }
18452        EditorSettings::get_global(cx).gutter.line_numbers
18453    }
18454
18455    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18456        self.use_relative_line_numbers
18457            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18458    }
18459
18460    pub fn toggle_relative_line_numbers(
18461        &mut self,
18462        _: &ToggleRelativeLineNumbers,
18463        _: &mut Window,
18464        cx: &mut Context<Self>,
18465    ) {
18466        let is_relative = self.should_use_relative_line_numbers(cx);
18467        self.set_relative_line_number(Some(!is_relative), cx)
18468    }
18469
18470    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18471        self.use_relative_line_numbers = is_relative;
18472        cx.notify();
18473    }
18474
18475    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18476        self.show_gutter = show_gutter;
18477        cx.notify();
18478    }
18479
18480    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18481        self.show_scrollbars = ScrollbarAxes {
18482            horizontal: show,
18483            vertical: show,
18484        };
18485        cx.notify();
18486    }
18487
18488    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18489        self.show_scrollbars.vertical = show;
18490        cx.notify();
18491    }
18492
18493    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18494        self.show_scrollbars.horizontal = show;
18495        cx.notify();
18496    }
18497
18498    pub fn set_minimap_visibility(
18499        &mut self,
18500        minimap_visibility: MinimapVisibility,
18501        window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        if self.minimap_visibility != minimap_visibility {
18505            if minimap_visibility.visible() && self.minimap.is_none() {
18506                let minimap_settings = EditorSettings::get_global(cx).minimap;
18507                self.minimap =
18508                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18509            }
18510            self.minimap_visibility = minimap_visibility;
18511            cx.notify();
18512        }
18513    }
18514
18515    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18516        self.set_show_scrollbars(false, cx);
18517        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18518    }
18519
18520    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18521        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18522    }
18523
18524    /// Normally the text in full mode and auto height editors is padded on the
18525    /// left side by roughly half a character width for improved hit testing.
18526    ///
18527    /// Use this method to disable this for cases where this is not wanted (e.g.
18528    /// if you want to align the editor text with some other text above or below)
18529    /// or if you want to add this padding to single-line editors.
18530    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18531        self.offset_content = offset_content;
18532        cx.notify();
18533    }
18534
18535    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18536        self.show_line_numbers = Some(show_line_numbers);
18537        cx.notify();
18538    }
18539
18540    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18541        self.disable_expand_excerpt_buttons = true;
18542        cx.notify();
18543    }
18544
18545    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18546        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18547        cx.notify();
18548    }
18549
18550    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18551        self.show_code_actions = Some(show_code_actions);
18552        cx.notify();
18553    }
18554
18555    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18556        self.show_runnables = Some(show_runnables);
18557        cx.notify();
18558    }
18559
18560    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18561        self.show_breakpoints = Some(show_breakpoints);
18562        cx.notify();
18563    }
18564
18565    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18566        if self.display_map.read(cx).masked != masked {
18567            self.display_map.update(cx, |map, _| map.masked = masked);
18568        }
18569        cx.notify()
18570    }
18571
18572    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18573        self.show_wrap_guides = Some(show_wrap_guides);
18574        cx.notify();
18575    }
18576
18577    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18578        self.show_indent_guides = Some(show_indent_guides);
18579        cx.notify();
18580    }
18581
18582    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18583        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18584            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18585                && let Some(dir) = file.abs_path(cx).parent()
18586            {
18587                return Some(dir.to_owned());
18588            }
18589
18590            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18591                return Some(project_path.path.to_path_buf());
18592            }
18593        }
18594
18595        None
18596    }
18597
18598    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18599        self.active_excerpt(cx)?
18600            .1
18601            .read(cx)
18602            .file()
18603            .and_then(|f| f.as_local())
18604    }
18605
18606    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18607        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18608            let buffer = buffer.read(cx);
18609            if let Some(project_path) = buffer.project_path(cx) {
18610                let project = self.project()?.read(cx);
18611                project.absolute_path(&project_path, cx)
18612            } else {
18613                buffer
18614                    .file()
18615                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18616            }
18617        })
18618    }
18619
18620    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18621        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18622            let project_path = buffer.read(cx).project_path(cx)?;
18623            let project = self.project()?.read(cx);
18624            let entry = project.entry_for_path(&project_path, cx)?;
18625            let path = entry.path.to_path_buf();
18626            Some(path)
18627        })
18628    }
18629
18630    pub fn reveal_in_finder(
18631        &mut self,
18632        _: &RevealInFileManager,
18633        _window: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        if let Some(target) = self.target_file(cx) {
18637            cx.reveal_path(&target.abs_path(cx));
18638        }
18639    }
18640
18641    pub fn copy_path(
18642        &mut self,
18643        _: &zed_actions::workspace::CopyPath,
18644        _window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        if let Some(path) = self.target_file_abs_path(cx)
18648            && let Some(path) = path.to_str()
18649        {
18650            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18651        }
18652    }
18653
18654    pub fn copy_relative_path(
18655        &mut self,
18656        _: &zed_actions::workspace::CopyRelativePath,
18657        _window: &mut Window,
18658        cx: &mut Context<Self>,
18659    ) {
18660        if let Some(path) = self.target_file_path(cx)
18661            && let Some(path) = path.to_str()
18662        {
18663            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18664        }
18665    }
18666
18667    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18668        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18669            buffer.read(cx).project_path(cx)
18670        } else {
18671            None
18672        }
18673    }
18674
18675    // Returns true if the editor handled a go-to-line request
18676    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18677        maybe!({
18678            let breakpoint_store = self.breakpoint_store.as_ref()?;
18679
18680            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18681            else {
18682                self.clear_row_highlights::<ActiveDebugLine>();
18683                return None;
18684            };
18685
18686            let position = active_stack_frame.position;
18687            let buffer_id = position.buffer_id?;
18688            let snapshot = self
18689                .project
18690                .as_ref()?
18691                .read(cx)
18692                .buffer_for_id(buffer_id, cx)?
18693                .read(cx)
18694                .snapshot();
18695
18696            let mut handled = false;
18697            for (id, ExcerptRange { context, .. }) in
18698                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18699            {
18700                if context.start.cmp(&position, &snapshot).is_ge()
18701                    || context.end.cmp(&position, &snapshot).is_lt()
18702                {
18703                    continue;
18704                }
18705                let snapshot = self.buffer.read(cx).snapshot(cx);
18706                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18707
18708                handled = true;
18709                self.clear_row_highlights::<ActiveDebugLine>();
18710
18711                self.go_to_line::<ActiveDebugLine>(
18712                    multibuffer_anchor,
18713                    Some(cx.theme().colors().editor_debugger_active_line_background),
18714                    window,
18715                    cx,
18716                );
18717
18718                cx.notify();
18719            }
18720
18721            handled.then_some(())
18722        })
18723        .is_some()
18724    }
18725
18726    pub fn copy_file_name_without_extension(
18727        &mut self,
18728        _: &CopyFileNameWithoutExtension,
18729        _: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) {
18732        if let Some(file) = self.target_file(cx)
18733            && let Some(file_stem) = file.path().file_stem()
18734            && let Some(name) = file_stem.to_str()
18735        {
18736            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18737        }
18738    }
18739
18740    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18741        if let Some(file) = self.target_file(cx)
18742            && let Some(file_name) = file.path().file_name()
18743            && let Some(name) = file_name.to_str()
18744        {
18745            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18746        }
18747    }
18748
18749    pub fn toggle_git_blame(
18750        &mut self,
18751        _: &::git::Blame,
18752        window: &mut Window,
18753        cx: &mut Context<Self>,
18754    ) {
18755        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18756
18757        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18758            self.start_git_blame(true, window, cx);
18759        }
18760
18761        cx.notify();
18762    }
18763
18764    pub fn toggle_git_blame_inline(
18765        &mut self,
18766        _: &ToggleGitBlameInline,
18767        window: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) {
18770        self.toggle_git_blame_inline_internal(true, window, cx);
18771        cx.notify();
18772    }
18773
18774    pub fn open_git_blame_commit(
18775        &mut self,
18776        _: &OpenGitBlameCommit,
18777        window: &mut Window,
18778        cx: &mut Context<Self>,
18779    ) {
18780        self.open_git_blame_commit_internal(window, cx);
18781    }
18782
18783    fn open_git_blame_commit_internal(
18784        &mut self,
18785        window: &mut Window,
18786        cx: &mut Context<Self>,
18787    ) -> Option<()> {
18788        let blame = self.blame.as_ref()?;
18789        let snapshot = self.snapshot(window, cx);
18790        let cursor = self.selections.newest::<Point>(cx).head();
18791        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18792        let blame_entry = blame
18793            .update(cx, |blame, cx| {
18794                blame
18795                    .blame_for_rows(
18796                        &[RowInfo {
18797                            buffer_id: Some(buffer.remote_id()),
18798                            buffer_row: Some(point.row),
18799                            ..Default::default()
18800                        }],
18801                        cx,
18802                    )
18803                    .next()
18804            })
18805            .flatten()?;
18806        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18807        let repo = blame.read(cx).repository(cx)?;
18808        let workspace = self.workspace()?.downgrade();
18809        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18810        None
18811    }
18812
18813    pub fn git_blame_inline_enabled(&self) -> bool {
18814        self.git_blame_inline_enabled
18815    }
18816
18817    pub fn toggle_selection_menu(
18818        &mut self,
18819        _: &ToggleSelectionMenu,
18820        _: &mut Window,
18821        cx: &mut Context<Self>,
18822    ) {
18823        self.show_selection_menu = self
18824            .show_selection_menu
18825            .map(|show_selections_menu| !show_selections_menu)
18826            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18827
18828        cx.notify();
18829    }
18830
18831    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18832        self.show_selection_menu
18833            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18834    }
18835
18836    fn start_git_blame(
18837        &mut self,
18838        user_triggered: bool,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) {
18842        if let Some(project) = self.project() {
18843            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18844                return;
18845            };
18846
18847            if buffer.read(cx).file().is_none() {
18848                return;
18849            }
18850
18851            let focused = self.focus_handle(cx).contains_focused(window, cx);
18852
18853            let project = project.clone();
18854            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18855            self.blame_subscription =
18856                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18857            self.blame = Some(blame);
18858        }
18859    }
18860
18861    fn toggle_git_blame_inline_internal(
18862        &mut self,
18863        user_triggered: bool,
18864        window: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        if self.git_blame_inline_enabled {
18868            self.git_blame_inline_enabled = false;
18869            self.show_git_blame_inline = false;
18870            self.show_git_blame_inline_delay_task.take();
18871        } else {
18872            self.git_blame_inline_enabled = true;
18873            self.start_git_blame_inline(user_triggered, window, cx);
18874        }
18875
18876        cx.notify();
18877    }
18878
18879    fn start_git_blame_inline(
18880        &mut self,
18881        user_triggered: bool,
18882        window: &mut Window,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.start_git_blame(user_triggered, window, cx);
18886
18887        if ProjectSettings::get_global(cx)
18888            .git
18889            .inline_blame_delay()
18890            .is_some()
18891        {
18892            self.start_inline_blame_timer(window, cx);
18893        } else {
18894            self.show_git_blame_inline = true
18895        }
18896    }
18897
18898    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18899        self.blame.as_ref()
18900    }
18901
18902    pub fn show_git_blame_gutter(&self) -> bool {
18903        self.show_git_blame_gutter
18904    }
18905
18906    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18907        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18908    }
18909
18910    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18911        self.show_git_blame_inline
18912            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18913            && !self.newest_selection_head_on_empty_line(cx)
18914            && self.has_blame_entries(cx)
18915    }
18916
18917    fn has_blame_entries(&self, cx: &App) -> bool {
18918        self.blame()
18919            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18920    }
18921
18922    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18923        let cursor_anchor = self.selections.newest_anchor().head();
18924
18925        let snapshot = self.buffer.read(cx).snapshot(cx);
18926        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18927
18928        snapshot.line_len(buffer_row) == 0
18929    }
18930
18931    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18932        let buffer_and_selection = maybe!({
18933            let selection = self.selections.newest::<Point>(cx);
18934            let selection_range = selection.range();
18935
18936            let multi_buffer = self.buffer().read(cx);
18937            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18938            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18939
18940            let (buffer, range, _) = if selection.reversed {
18941                buffer_ranges.first()
18942            } else {
18943                buffer_ranges.last()
18944            }?;
18945
18946            let selection = text::ToPoint::to_point(&range.start, buffer).row
18947                ..text::ToPoint::to_point(&range.end, buffer).row;
18948            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
18949        });
18950
18951        let Some((buffer, selection)) = buffer_and_selection else {
18952            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18953        };
18954
18955        let Some(project) = self.project() else {
18956            return Task::ready(Err(anyhow!("editor does not have project")));
18957        };
18958
18959        project.update(cx, |project, cx| {
18960            project.get_permalink_to_line(&buffer, selection, cx)
18961        })
18962    }
18963
18964    pub fn copy_permalink_to_line(
18965        &mut self,
18966        _: &CopyPermalinkToLine,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        let permalink_task = self.get_permalink_to_line(cx);
18971        let workspace = self.workspace();
18972
18973        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18974            Ok(permalink) => {
18975                cx.update(|_, cx| {
18976                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18977                })
18978                .ok();
18979            }
18980            Err(err) => {
18981                let message = format!("Failed to copy permalink: {err}");
18982
18983                anyhow::Result::<()>::Err(err).log_err();
18984
18985                if let Some(workspace) = workspace {
18986                    workspace
18987                        .update_in(cx, |workspace, _, cx| {
18988                            struct CopyPermalinkToLine;
18989
18990                            workspace.show_toast(
18991                                Toast::new(
18992                                    NotificationId::unique::<CopyPermalinkToLine>(),
18993                                    message,
18994                                ),
18995                                cx,
18996                            )
18997                        })
18998                        .ok();
18999                }
19000            }
19001        })
19002        .detach();
19003    }
19004
19005    pub fn copy_file_location(
19006        &mut self,
19007        _: &CopyFileLocation,
19008        _: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19012        if let Some(file) = self.target_file(cx)
19013            && let Some(path) = file.path().to_str()
19014        {
19015            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19016        }
19017    }
19018
19019    pub fn open_permalink_to_line(
19020        &mut self,
19021        _: &OpenPermalinkToLine,
19022        window: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        let permalink_task = self.get_permalink_to_line(cx);
19026        let workspace = self.workspace();
19027
19028        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19029            Ok(permalink) => {
19030                cx.update(|_, cx| {
19031                    cx.open_url(permalink.as_ref());
19032                })
19033                .ok();
19034            }
19035            Err(err) => {
19036                let message = format!("Failed to open permalink: {err}");
19037
19038                anyhow::Result::<()>::Err(err).log_err();
19039
19040                if let Some(workspace) = workspace {
19041                    workspace
19042                        .update(cx, |workspace, cx| {
19043                            struct OpenPermalinkToLine;
19044
19045                            workspace.show_toast(
19046                                Toast::new(
19047                                    NotificationId::unique::<OpenPermalinkToLine>(),
19048                                    message,
19049                                ),
19050                                cx,
19051                            )
19052                        })
19053                        .ok();
19054                }
19055            }
19056        })
19057        .detach();
19058    }
19059
19060    pub fn insert_uuid_v4(
19061        &mut self,
19062        _: &InsertUuidV4,
19063        window: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        self.insert_uuid(UuidVersion::V4, window, cx);
19067    }
19068
19069    pub fn insert_uuid_v7(
19070        &mut self,
19071        _: &InsertUuidV7,
19072        window: &mut Window,
19073        cx: &mut Context<Self>,
19074    ) {
19075        self.insert_uuid(UuidVersion::V7, window, cx);
19076    }
19077
19078    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19080        self.transact(window, cx, |this, window, cx| {
19081            let edits = this
19082                .selections
19083                .all::<Point>(cx)
19084                .into_iter()
19085                .map(|selection| {
19086                    let uuid = match version {
19087                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19088                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19089                    };
19090
19091                    (selection.range(), uuid.to_string())
19092                });
19093            this.edit(edits, cx);
19094            this.refresh_edit_prediction(true, false, window, cx);
19095        });
19096    }
19097
19098    pub fn open_selections_in_multibuffer(
19099        &mut self,
19100        _: &OpenSelectionsInMultibuffer,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        let multibuffer = self.buffer.read(cx);
19105
19106        let Some(buffer) = multibuffer.as_singleton() else {
19107            return;
19108        };
19109
19110        let Some(workspace) = self.workspace() else {
19111            return;
19112        };
19113
19114        let title = multibuffer.title(cx).to_string();
19115
19116        let locations = self
19117            .selections
19118            .all_anchors(cx)
19119            .iter()
19120            .map(|selection| Location {
19121                buffer: buffer.clone(),
19122                range: selection.start.text_anchor..selection.end.text_anchor,
19123            })
19124            .collect::<Vec<_>>();
19125
19126        cx.spawn_in(window, async move |_, cx| {
19127            workspace.update_in(cx, |workspace, window, cx| {
19128                Self::open_locations_in_multibuffer(
19129                    workspace,
19130                    locations,
19131                    format!("Selections for '{title}'"),
19132                    false,
19133                    MultibufferSelectionMode::All,
19134                    window,
19135                    cx,
19136                );
19137            })
19138        })
19139        .detach();
19140    }
19141
19142    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19143    /// last highlight added will be used.
19144    ///
19145    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19146    pub fn highlight_rows<T: 'static>(
19147        &mut self,
19148        range: Range<Anchor>,
19149        color: Hsla,
19150        options: RowHighlightOptions,
19151        cx: &mut Context<Self>,
19152    ) {
19153        let snapshot = self.buffer().read(cx).snapshot(cx);
19154        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19155        let ix = row_highlights.binary_search_by(|highlight| {
19156            Ordering::Equal
19157                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19158                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19159        });
19160
19161        if let Err(mut ix) = ix {
19162            let index = post_inc(&mut self.highlight_order);
19163
19164            // If this range intersects with the preceding highlight, then merge it with
19165            // the preceding highlight. Otherwise insert a new highlight.
19166            let mut merged = false;
19167            if ix > 0 {
19168                let prev_highlight = &mut row_highlights[ix - 1];
19169                if prev_highlight
19170                    .range
19171                    .end
19172                    .cmp(&range.start, &snapshot)
19173                    .is_ge()
19174                {
19175                    ix -= 1;
19176                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19177                        prev_highlight.range.end = range.end;
19178                    }
19179                    merged = true;
19180                    prev_highlight.index = index;
19181                    prev_highlight.color = color;
19182                    prev_highlight.options = options;
19183                }
19184            }
19185
19186            if !merged {
19187                row_highlights.insert(
19188                    ix,
19189                    RowHighlight {
19190                        range,
19191                        index,
19192                        color,
19193                        options,
19194                        type_id: TypeId::of::<T>(),
19195                    },
19196                );
19197            }
19198
19199            // If any of the following highlights intersect with this one, merge them.
19200            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19201                let highlight = &row_highlights[ix];
19202                if next_highlight
19203                    .range
19204                    .start
19205                    .cmp(&highlight.range.end, &snapshot)
19206                    .is_le()
19207                {
19208                    if next_highlight
19209                        .range
19210                        .end
19211                        .cmp(&highlight.range.end, &snapshot)
19212                        .is_gt()
19213                    {
19214                        row_highlights[ix].range.end = next_highlight.range.end;
19215                    }
19216                    row_highlights.remove(ix + 1);
19217                } else {
19218                    break;
19219                }
19220            }
19221        }
19222    }
19223
19224    /// Remove any highlighted row ranges of the given type that intersect the
19225    /// given ranges.
19226    pub fn remove_highlighted_rows<T: 'static>(
19227        &mut self,
19228        ranges_to_remove: Vec<Range<Anchor>>,
19229        cx: &mut Context<Self>,
19230    ) {
19231        let snapshot = self.buffer().read(cx).snapshot(cx);
19232        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19233        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19234        row_highlights.retain(|highlight| {
19235            while let Some(range_to_remove) = ranges_to_remove.peek() {
19236                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19237                    Ordering::Less | Ordering::Equal => {
19238                        ranges_to_remove.next();
19239                    }
19240                    Ordering::Greater => {
19241                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19242                            Ordering::Less | Ordering::Equal => {
19243                                return false;
19244                            }
19245                            Ordering::Greater => break,
19246                        }
19247                    }
19248                }
19249            }
19250
19251            true
19252        })
19253    }
19254
19255    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19256    pub fn clear_row_highlights<T: 'static>(&mut self) {
19257        self.highlighted_rows.remove(&TypeId::of::<T>());
19258    }
19259
19260    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19261    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19262        self.highlighted_rows
19263            .get(&TypeId::of::<T>())
19264            .map_or(&[] as &[_], |vec| vec.as_slice())
19265            .iter()
19266            .map(|highlight| (highlight.range.clone(), highlight.color))
19267    }
19268
19269    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19270    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19271    /// Allows to ignore certain kinds of highlights.
19272    pub fn highlighted_display_rows(
19273        &self,
19274        window: &mut Window,
19275        cx: &mut App,
19276    ) -> BTreeMap<DisplayRow, LineHighlight> {
19277        let snapshot = self.snapshot(window, cx);
19278        let mut used_highlight_orders = HashMap::default();
19279        self.highlighted_rows
19280            .iter()
19281            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19282            .fold(
19283                BTreeMap::<DisplayRow, LineHighlight>::new(),
19284                |mut unique_rows, highlight| {
19285                    let start = highlight.range.start.to_display_point(&snapshot);
19286                    let end = highlight.range.end.to_display_point(&snapshot);
19287                    let start_row = start.row().0;
19288                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19289                        && end.column() == 0
19290                    {
19291                        end.row().0.saturating_sub(1)
19292                    } else {
19293                        end.row().0
19294                    };
19295                    for row in start_row..=end_row {
19296                        let used_index =
19297                            used_highlight_orders.entry(row).or_insert(highlight.index);
19298                        if highlight.index >= *used_index {
19299                            *used_index = highlight.index;
19300                            unique_rows.insert(
19301                                DisplayRow(row),
19302                                LineHighlight {
19303                                    include_gutter: highlight.options.include_gutter,
19304                                    border: None,
19305                                    background: highlight.color.into(),
19306                                    type_id: Some(highlight.type_id),
19307                                },
19308                            );
19309                        }
19310                    }
19311                    unique_rows
19312                },
19313            )
19314    }
19315
19316    pub fn highlighted_display_row_for_autoscroll(
19317        &self,
19318        snapshot: &DisplaySnapshot,
19319    ) -> Option<DisplayRow> {
19320        self.highlighted_rows
19321            .values()
19322            .flat_map(|highlighted_rows| highlighted_rows.iter())
19323            .filter_map(|highlight| {
19324                if highlight.options.autoscroll {
19325                    Some(highlight.range.start.to_display_point(snapshot).row())
19326                } else {
19327                    None
19328                }
19329            })
19330            .min()
19331    }
19332
19333    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19334        self.highlight_background::<SearchWithinRange>(
19335            ranges,
19336            |colors| colors.colors().editor_document_highlight_read_background,
19337            cx,
19338        )
19339    }
19340
19341    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19342        self.breadcrumb_header = Some(new_header);
19343    }
19344
19345    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19346        self.clear_background_highlights::<SearchWithinRange>(cx);
19347    }
19348
19349    pub fn highlight_background<T: 'static>(
19350        &mut self,
19351        ranges: &[Range<Anchor>],
19352        color_fetcher: fn(&Theme) -> Hsla,
19353        cx: &mut Context<Self>,
19354    ) {
19355        self.background_highlights.insert(
19356            HighlightKey::Type(TypeId::of::<T>()),
19357            (color_fetcher, Arc::from(ranges)),
19358        );
19359        self.scrollbar_marker_state.dirty = true;
19360        cx.notify();
19361    }
19362
19363    pub fn highlight_background_key<T: 'static>(
19364        &mut self,
19365        key: usize,
19366        ranges: &[Range<Anchor>],
19367        color_fetcher: fn(&Theme) -> Hsla,
19368        cx: &mut Context<Self>,
19369    ) {
19370        self.background_highlights.insert(
19371            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19372            (color_fetcher, Arc::from(ranges)),
19373        );
19374        self.scrollbar_marker_state.dirty = true;
19375        cx.notify();
19376    }
19377
19378    pub fn clear_background_highlights<T: 'static>(
19379        &mut self,
19380        cx: &mut Context<Self>,
19381    ) -> Option<BackgroundHighlight> {
19382        let text_highlights = self
19383            .background_highlights
19384            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19385        if !text_highlights.1.is_empty() {
19386            self.scrollbar_marker_state.dirty = true;
19387            cx.notify();
19388        }
19389        Some(text_highlights)
19390    }
19391
19392    pub fn highlight_gutter<T: 'static>(
19393        &mut self,
19394        ranges: impl Into<Vec<Range<Anchor>>>,
19395        color_fetcher: fn(&App) -> Hsla,
19396        cx: &mut Context<Self>,
19397    ) {
19398        self.gutter_highlights
19399            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19400        cx.notify();
19401    }
19402
19403    pub fn clear_gutter_highlights<T: 'static>(
19404        &mut self,
19405        cx: &mut Context<Self>,
19406    ) -> Option<GutterHighlight> {
19407        cx.notify();
19408        self.gutter_highlights.remove(&TypeId::of::<T>())
19409    }
19410
19411    pub fn insert_gutter_highlight<T: 'static>(
19412        &mut self,
19413        range: Range<Anchor>,
19414        color_fetcher: fn(&App) -> Hsla,
19415        cx: &mut Context<Self>,
19416    ) {
19417        let snapshot = self.buffer().read(cx).snapshot(cx);
19418        let mut highlights = self
19419            .gutter_highlights
19420            .remove(&TypeId::of::<T>())
19421            .map(|(_, highlights)| highlights)
19422            .unwrap_or_default();
19423        let ix = highlights.binary_search_by(|highlight| {
19424            Ordering::Equal
19425                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19426                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19427        });
19428        if let Err(ix) = ix {
19429            highlights.insert(ix, range);
19430        }
19431        self.gutter_highlights
19432            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19433    }
19434
19435    pub fn remove_gutter_highlights<T: 'static>(
19436        &mut self,
19437        ranges_to_remove: Vec<Range<Anchor>>,
19438        cx: &mut Context<Self>,
19439    ) {
19440        let snapshot = self.buffer().read(cx).snapshot(cx);
19441        let Some((color_fetcher, mut gutter_highlights)) =
19442            self.gutter_highlights.remove(&TypeId::of::<T>())
19443        else {
19444            return;
19445        };
19446        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19447        gutter_highlights.retain(|highlight| {
19448            while let Some(range_to_remove) = ranges_to_remove.peek() {
19449                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19450                    Ordering::Less | Ordering::Equal => {
19451                        ranges_to_remove.next();
19452                    }
19453                    Ordering::Greater => {
19454                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19455                            Ordering::Less | Ordering::Equal => {
19456                                return false;
19457                            }
19458                            Ordering::Greater => break,
19459                        }
19460                    }
19461                }
19462            }
19463
19464            true
19465        });
19466        self.gutter_highlights
19467            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19468    }
19469
19470    #[cfg(feature = "test-support")]
19471    pub fn all_text_highlights(
19472        &self,
19473        window: &mut Window,
19474        cx: &mut Context<Self>,
19475    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19476        let snapshot = self.snapshot(window, cx);
19477        self.display_map.update(cx, |display_map, _| {
19478            display_map
19479                .all_text_highlights()
19480                .map(|highlight| {
19481                    let (style, ranges) = highlight.as_ref();
19482                    (
19483                        *style,
19484                        ranges
19485                            .iter()
19486                            .map(|range| range.clone().to_display_points(&snapshot))
19487                            .collect(),
19488                    )
19489                })
19490                .collect()
19491        })
19492    }
19493
19494    #[cfg(feature = "test-support")]
19495    pub fn all_text_background_highlights(
19496        &self,
19497        window: &mut Window,
19498        cx: &mut Context<Self>,
19499    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19500        let snapshot = self.snapshot(window, cx);
19501        let buffer = &snapshot.buffer_snapshot;
19502        let start = buffer.anchor_before(0);
19503        let end = buffer.anchor_after(buffer.len());
19504        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19505    }
19506
19507    #[cfg(feature = "test-support")]
19508    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19509        let snapshot = self.buffer().read(cx).snapshot(cx);
19510
19511        let highlights = self
19512            .background_highlights
19513            .get(&HighlightKey::Type(TypeId::of::<
19514                items::BufferSearchHighlights,
19515            >()));
19516
19517        if let Some((_color, ranges)) = highlights {
19518            ranges
19519                .iter()
19520                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19521                .collect_vec()
19522        } else {
19523            vec![]
19524        }
19525    }
19526
19527    fn document_highlights_for_position<'a>(
19528        &'a self,
19529        position: Anchor,
19530        buffer: &'a MultiBufferSnapshot,
19531    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19532        let read_highlights = self
19533            .background_highlights
19534            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19535            .map(|h| &h.1);
19536        let write_highlights = self
19537            .background_highlights
19538            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19539            .map(|h| &h.1);
19540        let left_position = position.bias_left(buffer);
19541        let right_position = position.bias_right(buffer);
19542        read_highlights
19543            .into_iter()
19544            .chain(write_highlights)
19545            .flat_map(move |ranges| {
19546                let start_ix = match ranges.binary_search_by(|probe| {
19547                    let cmp = probe.end.cmp(&left_position, buffer);
19548                    if cmp.is_ge() {
19549                        Ordering::Greater
19550                    } else {
19551                        Ordering::Less
19552                    }
19553                }) {
19554                    Ok(i) | Err(i) => i,
19555                };
19556
19557                ranges[start_ix..]
19558                    .iter()
19559                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19560            })
19561    }
19562
19563    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19564        self.background_highlights
19565            .get(&HighlightKey::Type(TypeId::of::<T>()))
19566            .is_some_and(|(_, highlights)| !highlights.is_empty())
19567    }
19568
19569    pub fn background_highlights_in_range(
19570        &self,
19571        search_range: Range<Anchor>,
19572        display_snapshot: &DisplaySnapshot,
19573        theme: &Theme,
19574    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19575        let mut results = Vec::new();
19576        for (color_fetcher, ranges) in self.background_highlights.values() {
19577            let color = color_fetcher(theme);
19578            let start_ix = match ranges.binary_search_by(|probe| {
19579                let cmp = probe
19580                    .end
19581                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19582                if cmp.is_gt() {
19583                    Ordering::Greater
19584                } else {
19585                    Ordering::Less
19586                }
19587            }) {
19588                Ok(i) | Err(i) => i,
19589            };
19590            for range in &ranges[start_ix..] {
19591                if range
19592                    .start
19593                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19594                    .is_ge()
19595                {
19596                    break;
19597                }
19598
19599                let start = range.start.to_display_point(display_snapshot);
19600                let end = range.end.to_display_point(display_snapshot);
19601                results.push((start..end, color))
19602            }
19603        }
19604        results
19605    }
19606
19607    pub fn background_highlight_row_ranges<T: 'static>(
19608        &self,
19609        search_range: Range<Anchor>,
19610        display_snapshot: &DisplaySnapshot,
19611        count: usize,
19612    ) -> Vec<RangeInclusive<DisplayPoint>> {
19613        let mut results = Vec::new();
19614        let Some((_, ranges)) = self
19615            .background_highlights
19616            .get(&HighlightKey::Type(TypeId::of::<T>()))
19617        else {
19618            return vec![];
19619        };
19620
19621        let start_ix = match ranges.binary_search_by(|probe| {
19622            let cmp = probe
19623                .end
19624                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19625            if cmp.is_gt() {
19626                Ordering::Greater
19627            } else {
19628                Ordering::Less
19629            }
19630        }) {
19631            Ok(i) | Err(i) => i,
19632        };
19633        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19634            if let (Some(start_display), Some(end_display)) = (start, end) {
19635                results.push(
19636                    start_display.to_display_point(display_snapshot)
19637                        ..=end_display.to_display_point(display_snapshot),
19638                );
19639            }
19640        };
19641        let mut start_row: Option<Point> = None;
19642        let mut end_row: Option<Point> = None;
19643        if ranges.len() > count {
19644            return Vec::new();
19645        }
19646        for range in &ranges[start_ix..] {
19647            if range
19648                .start
19649                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19650                .is_ge()
19651            {
19652                break;
19653            }
19654            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19655            if let Some(current_row) = &end_row
19656                && end.row == current_row.row
19657            {
19658                continue;
19659            }
19660            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19661            if start_row.is_none() {
19662                assert_eq!(end_row, None);
19663                start_row = Some(start);
19664                end_row = Some(end);
19665                continue;
19666            }
19667            if let Some(current_end) = end_row.as_mut() {
19668                if start.row > current_end.row + 1 {
19669                    push_region(start_row, end_row);
19670                    start_row = Some(start);
19671                    end_row = Some(end);
19672                } else {
19673                    // Merge two hunks.
19674                    *current_end = end;
19675                }
19676            } else {
19677                unreachable!();
19678            }
19679        }
19680        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19681        push_region(start_row, end_row);
19682        results
19683    }
19684
19685    pub fn gutter_highlights_in_range(
19686        &self,
19687        search_range: Range<Anchor>,
19688        display_snapshot: &DisplaySnapshot,
19689        cx: &App,
19690    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19691        let mut results = Vec::new();
19692        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19693            let color = color_fetcher(cx);
19694            let start_ix = match ranges.binary_search_by(|probe| {
19695                let cmp = probe
19696                    .end
19697                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19698                if cmp.is_gt() {
19699                    Ordering::Greater
19700                } else {
19701                    Ordering::Less
19702                }
19703            }) {
19704                Ok(i) | Err(i) => i,
19705            };
19706            for range in &ranges[start_ix..] {
19707                if range
19708                    .start
19709                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19710                    .is_ge()
19711                {
19712                    break;
19713                }
19714
19715                let start = range.start.to_display_point(display_snapshot);
19716                let end = range.end.to_display_point(display_snapshot);
19717                results.push((start..end, color))
19718            }
19719        }
19720        results
19721    }
19722
19723    /// Get the text ranges corresponding to the redaction query
19724    pub fn redacted_ranges(
19725        &self,
19726        search_range: Range<Anchor>,
19727        display_snapshot: &DisplaySnapshot,
19728        cx: &App,
19729    ) -> Vec<Range<DisplayPoint>> {
19730        display_snapshot
19731            .buffer_snapshot
19732            .redacted_ranges(search_range, |file| {
19733                if let Some(file) = file {
19734                    file.is_private()
19735                        && EditorSettings::get(
19736                            Some(SettingsLocation {
19737                                worktree_id: file.worktree_id(cx),
19738                                path: file.path().as_ref(),
19739                            }),
19740                            cx,
19741                        )
19742                        .redact_private_values
19743                } else {
19744                    false
19745                }
19746            })
19747            .map(|range| {
19748                range.start.to_display_point(display_snapshot)
19749                    ..range.end.to_display_point(display_snapshot)
19750            })
19751            .collect()
19752    }
19753
19754    pub fn highlight_text_key<T: 'static>(
19755        &mut self,
19756        key: usize,
19757        ranges: Vec<Range<Anchor>>,
19758        style: HighlightStyle,
19759        cx: &mut Context<Self>,
19760    ) {
19761        self.display_map.update(cx, |map, _| {
19762            map.highlight_text(
19763                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19764                ranges,
19765                style,
19766            );
19767        });
19768        cx.notify();
19769    }
19770
19771    pub fn highlight_text<T: 'static>(
19772        &mut self,
19773        ranges: Vec<Range<Anchor>>,
19774        style: HighlightStyle,
19775        cx: &mut Context<Self>,
19776    ) {
19777        self.display_map.update(cx, |map, _| {
19778            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19779        });
19780        cx.notify();
19781    }
19782
19783    pub(crate) fn highlight_inlays<T: 'static>(
19784        &mut self,
19785        highlights: Vec<InlayHighlight>,
19786        style: HighlightStyle,
19787        cx: &mut Context<Self>,
19788    ) {
19789        self.display_map.update(cx, |map, _| {
19790            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19791        });
19792        cx.notify();
19793    }
19794
19795    pub fn text_highlights<'a, T: 'static>(
19796        &'a self,
19797        cx: &'a App,
19798    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19799        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19800    }
19801
19802    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19803        let cleared = self
19804            .display_map
19805            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19806        if cleared {
19807            cx.notify();
19808        }
19809    }
19810
19811    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19812        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19813            && self.focus_handle.is_focused(window)
19814    }
19815
19816    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19817        self.show_cursor_when_unfocused = is_enabled;
19818        cx.notify();
19819    }
19820
19821    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19822        cx.notify();
19823    }
19824
19825    fn on_debug_session_event(
19826        &mut self,
19827        _session: Entity<Session>,
19828        event: &SessionEvent,
19829        cx: &mut Context<Self>,
19830    ) {
19831        if let SessionEvent::InvalidateInlineValue = event {
19832            self.refresh_inline_values(cx);
19833        }
19834    }
19835
19836    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19837        let Some(project) = self.project.clone() else {
19838            return;
19839        };
19840
19841        if !self.inline_value_cache.enabled {
19842            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19843            self.splice_inlays(&inlays, Vec::new(), cx);
19844            return;
19845        }
19846
19847        let current_execution_position = self
19848            .highlighted_rows
19849            .get(&TypeId::of::<ActiveDebugLine>())
19850            .and_then(|lines| lines.last().map(|line| line.range.end));
19851
19852        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19853            let inline_values = editor
19854                .update(cx, |editor, cx| {
19855                    let Some(current_execution_position) = current_execution_position else {
19856                        return Some(Task::ready(Ok(Vec::new())));
19857                    };
19858
19859                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19860                        let snapshot = buffer.snapshot(cx);
19861
19862                        let excerpt = snapshot.excerpt_containing(
19863                            current_execution_position..current_execution_position,
19864                        )?;
19865
19866                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19867                    })?;
19868
19869                    let range =
19870                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19871
19872                    project.inline_values(buffer, range, cx)
19873                })
19874                .ok()
19875                .flatten()?
19876                .await
19877                .context("refreshing debugger inlays")
19878                .log_err()?;
19879
19880            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19881
19882            for (buffer_id, inline_value) in inline_values
19883                .into_iter()
19884                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19885            {
19886                buffer_inline_values
19887                    .entry(buffer_id)
19888                    .or_default()
19889                    .push(inline_value);
19890            }
19891
19892            editor
19893                .update(cx, |editor, cx| {
19894                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19895                    let mut new_inlays = Vec::default();
19896
19897                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19898                        let buffer_id = buffer_snapshot.remote_id();
19899                        buffer_inline_values
19900                            .get(&buffer_id)
19901                            .into_iter()
19902                            .flatten()
19903                            .for_each(|hint| {
19904                                let inlay = Inlay::debugger(
19905                                    post_inc(&mut editor.next_inlay_id),
19906                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19907                                    hint.text(),
19908                                );
19909                                if !inlay.text.chars().contains(&'\n') {
19910                                    new_inlays.push(inlay);
19911                                }
19912                            });
19913                    }
19914
19915                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19916                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19917
19918                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19919                })
19920                .ok()?;
19921            Some(())
19922        });
19923    }
19924
19925    fn on_buffer_event(
19926        &mut self,
19927        multibuffer: &Entity<MultiBuffer>,
19928        event: &multi_buffer::Event,
19929        window: &mut Window,
19930        cx: &mut Context<Self>,
19931    ) {
19932        match event {
19933            multi_buffer::Event::Edited {
19934                singleton_buffer_edited,
19935                edited_buffer,
19936            } => {
19937                self.scrollbar_marker_state.dirty = true;
19938                self.active_indent_guides_state.dirty = true;
19939                self.refresh_active_diagnostics(cx);
19940                self.refresh_code_actions(window, cx);
19941                self.refresh_selected_text_highlights(true, window, cx);
19942                self.refresh_single_line_folds(window, cx);
19943                refresh_matching_bracket_highlights(self, window, cx);
19944                if self.has_active_edit_prediction() {
19945                    self.update_visible_edit_prediction(window, cx);
19946                }
19947                if let Some(project) = self.project.as_ref()
19948                    && let Some(edited_buffer) = edited_buffer
19949                {
19950                    project.update(cx, |project, cx| {
19951                        self.registered_buffers
19952                            .entry(edited_buffer.read(cx).remote_id())
19953                            .or_insert_with(|| {
19954                                project.register_buffer_with_language_servers(edited_buffer, cx)
19955                            });
19956                    });
19957                }
19958                cx.emit(EditorEvent::BufferEdited);
19959                cx.emit(SearchEvent::MatchesInvalidated);
19960
19961                if let Some(buffer) = edited_buffer {
19962                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19963                }
19964
19965                if *singleton_buffer_edited {
19966                    if let Some(buffer) = edited_buffer
19967                        && buffer.read(cx).file().is_none()
19968                    {
19969                        cx.emit(EditorEvent::TitleChanged);
19970                    }
19971                    if let Some(project) = &self.project {
19972                        #[allow(clippy::mutable_key_type)]
19973                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19974                            multibuffer
19975                                .all_buffers()
19976                                .into_iter()
19977                                .filter_map(|buffer| {
19978                                    buffer.update(cx, |buffer, cx| {
19979                                        let language = buffer.language()?;
19980                                        let should_discard = project.update(cx, |project, cx| {
19981                                            project.is_local()
19982                                                && !project.has_language_servers_for(buffer, cx)
19983                                        });
19984                                        should_discard.not().then_some(language.clone())
19985                                    })
19986                                })
19987                                .collect::<HashSet<_>>()
19988                        });
19989                        if !languages_affected.is_empty() {
19990                            self.refresh_inlay_hints(
19991                                InlayHintRefreshReason::BufferEdited(languages_affected),
19992                                cx,
19993                            );
19994                        }
19995                    }
19996                }
19997
19998                let Some(project) = &self.project else { return };
19999                let (telemetry, is_via_ssh) = {
20000                    let project = project.read(cx);
20001                    let telemetry = project.client().telemetry().clone();
20002                    let is_via_ssh = project.is_via_ssh();
20003                    (telemetry, is_via_ssh)
20004                };
20005                refresh_linked_ranges(self, window, cx);
20006                telemetry.log_edit_event("editor", is_via_ssh);
20007            }
20008            multi_buffer::Event::ExcerptsAdded {
20009                buffer,
20010                predecessor,
20011                excerpts,
20012            } => {
20013                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20014                let buffer_id = buffer.read(cx).remote_id();
20015                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20016                    && let Some(project) = &self.project
20017                {
20018                    update_uncommitted_diff_for_buffer(
20019                        cx.entity(),
20020                        project,
20021                        [buffer.clone()],
20022                        self.buffer.clone(),
20023                        cx,
20024                    )
20025                    .detach();
20026                }
20027                self.update_lsp_data(false, Some(buffer_id), window, cx);
20028                cx.emit(EditorEvent::ExcerptsAdded {
20029                    buffer: buffer.clone(),
20030                    predecessor: *predecessor,
20031                    excerpts: excerpts.clone(),
20032                });
20033                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20034            }
20035            multi_buffer::Event::ExcerptsRemoved {
20036                ids,
20037                removed_buffer_ids,
20038            } => {
20039                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20040                let buffer = self.buffer.read(cx);
20041                self.registered_buffers
20042                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20043                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20044                cx.emit(EditorEvent::ExcerptsRemoved {
20045                    ids: ids.clone(),
20046                    removed_buffer_ids: removed_buffer_ids.clone(),
20047                });
20048            }
20049            multi_buffer::Event::ExcerptsEdited {
20050                excerpt_ids,
20051                buffer_ids,
20052            } => {
20053                self.display_map.update(cx, |map, cx| {
20054                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20055                });
20056                cx.emit(EditorEvent::ExcerptsEdited {
20057                    ids: excerpt_ids.clone(),
20058                });
20059            }
20060            multi_buffer::Event::ExcerptsExpanded { ids } => {
20061                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20062                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20063            }
20064            multi_buffer::Event::Reparsed(buffer_id) => {
20065                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20066                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20067
20068                cx.emit(EditorEvent::Reparsed(*buffer_id));
20069            }
20070            multi_buffer::Event::DiffHunksToggled => {
20071                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20072            }
20073            multi_buffer::Event::LanguageChanged(buffer_id) => {
20074                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20075                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20076                cx.emit(EditorEvent::Reparsed(*buffer_id));
20077                cx.notify();
20078            }
20079            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20080            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20081            multi_buffer::Event::FileHandleChanged
20082            | multi_buffer::Event::Reloaded
20083            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20084            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20085            multi_buffer::Event::DiagnosticsUpdated => {
20086                self.update_diagnostics_state(window, cx);
20087            }
20088            _ => {}
20089        };
20090    }
20091
20092    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20093        if !self.diagnostics_enabled() {
20094            return;
20095        }
20096        self.refresh_active_diagnostics(cx);
20097        self.refresh_inline_diagnostics(true, window, cx);
20098        self.scrollbar_marker_state.dirty = true;
20099        cx.notify();
20100    }
20101
20102    pub fn start_temporary_diff_override(&mut self) {
20103        self.load_diff_task.take();
20104        self.temporary_diff_override = true;
20105    }
20106
20107    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20108        self.temporary_diff_override = false;
20109        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20110        self.buffer.update(cx, |buffer, cx| {
20111            buffer.set_all_diff_hunks_collapsed(cx);
20112        });
20113
20114        if let Some(project) = self.project.clone() {
20115            self.load_diff_task = Some(
20116                update_uncommitted_diff_for_buffer(
20117                    cx.entity(),
20118                    &project,
20119                    self.buffer.read(cx).all_buffers(),
20120                    self.buffer.clone(),
20121                    cx,
20122                )
20123                .shared(),
20124            );
20125        }
20126    }
20127
20128    fn on_display_map_changed(
20129        &mut self,
20130        _: Entity<DisplayMap>,
20131        _: &mut Window,
20132        cx: &mut Context<Self>,
20133    ) {
20134        cx.notify();
20135    }
20136
20137    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20138        if self.diagnostics_enabled() {
20139            let new_severity = EditorSettings::get_global(cx)
20140                .diagnostics_max_severity
20141                .unwrap_or(DiagnosticSeverity::Hint);
20142            self.set_max_diagnostics_severity(new_severity, cx);
20143        }
20144        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20145        self.update_edit_prediction_settings(cx);
20146        self.refresh_edit_prediction(true, false, window, cx);
20147        self.refresh_inline_values(cx);
20148        self.refresh_inlay_hints(
20149            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20150                self.selections.newest_anchor().head(),
20151                &self.buffer.read(cx).snapshot(cx),
20152                cx,
20153            )),
20154            cx,
20155        );
20156
20157        let old_cursor_shape = self.cursor_shape;
20158        let old_show_breadcrumbs = self.show_breadcrumbs;
20159
20160        {
20161            let editor_settings = EditorSettings::get_global(cx);
20162            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20163            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20164            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20165            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20166        }
20167
20168        if old_cursor_shape != self.cursor_shape {
20169            cx.emit(EditorEvent::CursorShapeChanged);
20170        }
20171
20172        if old_show_breadcrumbs != self.show_breadcrumbs {
20173            cx.emit(EditorEvent::BreadcrumbsChanged);
20174        }
20175
20176        let project_settings = ProjectSettings::get_global(cx);
20177        self.serialize_dirty_buffers =
20178            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20179
20180        if self.mode.is_full() {
20181            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20182            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20183            if self.show_inline_diagnostics != show_inline_diagnostics {
20184                self.show_inline_diagnostics = show_inline_diagnostics;
20185                self.refresh_inline_diagnostics(false, window, cx);
20186            }
20187
20188            if self.git_blame_inline_enabled != inline_blame_enabled {
20189                self.toggle_git_blame_inline_internal(false, window, cx);
20190            }
20191
20192            let minimap_settings = EditorSettings::get_global(cx).minimap;
20193            if self.minimap_visibility != MinimapVisibility::Disabled {
20194                if self.minimap_visibility.settings_visibility()
20195                    != minimap_settings.minimap_enabled()
20196                {
20197                    self.set_minimap_visibility(
20198                        MinimapVisibility::for_mode(self.mode(), cx),
20199                        window,
20200                        cx,
20201                    );
20202                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20203                    minimap_entity.update(cx, |minimap_editor, cx| {
20204                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20205                    })
20206                }
20207            }
20208        }
20209
20210        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20211            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20212        }) {
20213            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20214                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20215            }
20216            self.refresh_colors(false, None, window, cx);
20217        }
20218
20219        cx.notify();
20220    }
20221
20222    pub fn set_searchable(&mut self, searchable: bool) {
20223        self.searchable = searchable;
20224    }
20225
20226    pub fn searchable(&self) -> bool {
20227        self.searchable
20228    }
20229
20230    fn open_proposed_changes_editor(
20231        &mut self,
20232        _: &OpenProposedChangesEditor,
20233        window: &mut Window,
20234        cx: &mut Context<Self>,
20235    ) {
20236        let Some(workspace) = self.workspace() else {
20237            cx.propagate();
20238            return;
20239        };
20240
20241        let selections = self.selections.all::<usize>(cx);
20242        let multi_buffer = self.buffer.read(cx);
20243        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20244        let mut new_selections_by_buffer = HashMap::default();
20245        for selection in selections {
20246            for (buffer, range, _) in
20247                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20248            {
20249                let mut range = range.to_point(buffer);
20250                range.start.column = 0;
20251                range.end.column = buffer.line_len(range.end.row);
20252                new_selections_by_buffer
20253                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20254                    .or_insert(Vec::new())
20255                    .push(range)
20256            }
20257        }
20258
20259        let proposed_changes_buffers = new_selections_by_buffer
20260            .into_iter()
20261            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20262            .collect::<Vec<_>>();
20263        let proposed_changes_editor = cx.new(|cx| {
20264            ProposedChangesEditor::new(
20265                "Proposed changes",
20266                proposed_changes_buffers,
20267                self.project.clone(),
20268                window,
20269                cx,
20270            )
20271        });
20272
20273        window.defer(cx, move |window, cx| {
20274            workspace.update(cx, |workspace, cx| {
20275                workspace.active_pane().update(cx, |pane, cx| {
20276                    pane.add_item(
20277                        Box::new(proposed_changes_editor),
20278                        true,
20279                        true,
20280                        None,
20281                        window,
20282                        cx,
20283                    );
20284                });
20285            });
20286        });
20287    }
20288
20289    pub fn open_excerpts_in_split(
20290        &mut self,
20291        _: &OpenExcerptsSplit,
20292        window: &mut Window,
20293        cx: &mut Context<Self>,
20294    ) {
20295        self.open_excerpts_common(None, true, window, cx)
20296    }
20297
20298    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20299        self.open_excerpts_common(None, false, window, cx)
20300    }
20301
20302    fn open_excerpts_common(
20303        &mut self,
20304        jump_data: Option<JumpData>,
20305        split: bool,
20306        window: &mut Window,
20307        cx: &mut Context<Self>,
20308    ) {
20309        let Some(workspace) = self.workspace() else {
20310            cx.propagate();
20311            return;
20312        };
20313
20314        if self.buffer.read(cx).is_singleton() {
20315            cx.propagate();
20316            return;
20317        }
20318
20319        let mut new_selections_by_buffer = HashMap::default();
20320        match &jump_data {
20321            Some(JumpData::MultiBufferPoint {
20322                excerpt_id,
20323                position,
20324                anchor,
20325                line_offset_from_top,
20326            }) => {
20327                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20328                if let Some(buffer) = multi_buffer_snapshot
20329                    .buffer_id_for_excerpt(*excerpt_id)
20330                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20331                {
20332                    let buffer_snapshot = buffer.read(cx).snapshot();
20333                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20334                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20335                    } else {
20336                        buffer_snapshot.clip_point(*position, Bias::Left)
20337                    };
20338                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20339                    new_selections_by_buffer.insert(
20340                        buffer,
20341                        (
20342                            vec![jump_to_offset..jump_to_offset],
20343                            Some(*line_offset_from_top),
20344                        ),
20345                    );
20346                }
20347            }
20348            Some(JumpData::MultiBufferRow {
20349                row,
20350                line_offset_from_top,
20351            }) => {
20352                let point = MultiBufferPoint::new(row.0, 0);
20353                if let Some((buffer, buffer_point, _)) =
20354                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20355                {
20356                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20357                    new_selections_by_buffer
20358                        .entry(buffer)
20359                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20360                        .0
20361                        .push(buffer_offset..buffer_offset)
20362                }
20363            }
20364            None => {
20365                let selections = self.selections.all::<usize>(cx);
20366                let multi_buffer = self.buffer.read(cx);
20367                for selection in selections {
20368                    for (snapshot, range, _, anchor) in multi_buffer
20369                        .snapshot(cx)
20370                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20371                    {
20372                        if let Some(anchor) = anchor {
20373                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20374                            else {
20375                                continue;
20376                            };
20377                            let offset = text::ToOffset::to_offset(
20378                                &anchor.text_anchor,
20379                                &buffer_handle.read(cx).snapshot(),
20380                            );
20381                            let range = offset..offset;
20382                            new_selections_by_buffer
20383                                .entry(buffer_handle)
20384                                .or_insert((Vec::new(), None))
20385                                .0
20386                                .push(range)
20387                        } else {
20388                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20389                            else {
20390                                continue;
20391                            };
20392                            new_selections_by_buffer
20393                                .entry(buffer_handle)
20394                                .or_insert((Vec::new(), None))
20395                                .0
20396                                .push(range)
20397                        }
20398                    }
20399                }
20400            }
20401        }
20402
20403        new_selections_by_buffer
20404            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20405
20406        if new_selections_by_buffer.is_empty() {
20407            return;
20408        }
20409
20410        // We defer the pane interaction because we ourselves are a workspace item
20411        // and activating a new item causes the pane to call a method on us reentrantly,
20412        // which panics if we're on the stack.
20413        window.defer(cx, move |window, cx| {
20414            workspace.update(cx, |workspace, cx| {
20415                let pane = if split {
20416                    workspace.adjacent_pane(window, cx)
20417                } else {
20418                    workspace.active_pane().clone()
20419                };
20420
20421                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20422                    let editor = buffer
20423                        .read(cx)
20424                        .file()
20425                        .is_none()
20426                        .then(|| {
20427                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20428                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20429                            // Instead, we try to activate the existing editor in the pane first.
20430                            let (editor, pane_item_index) =
20431                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20432                                    let editor = item.downcast::<Editor>()?;
20433                                    let singleton_buffer =
20434                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20435                                    if singleton_buffer == buffer {
20436                                        Some((editor, i))
20437                                    } else {
20438                                        None
20439                                    }
20440                                })?;
20441                            pane.update(cx, |pane, cx| {
20442                                pane.activate_item(pane_item_index, true, true, window, cx)
20443                            });
20444                            Some(editor)
20445                        })
20446                        .flatten()
20447                        .unwrap_or_else(|| {
20448                            workspace.open_project_item::<Self>(
20449                                pane.clone(),
20450                                buffer,
20451                                true,
20452                                true,
20453                                window,
20454                                cx,
20455                            )
20456                        });
20457
20458                    editor.update(cx, |editor, cx| {
20459                        let autoscroll = match scroll_offset {
20460                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20461                            None => Autoscroll::newest(),
20462                        };
20463                        let nav_history = editor.nav_history.take();
20464                        editor.change_selections(
20465                            SelectionEffects::scroll(autoscroll),
20466                            window,
20467                            cx,
20468                            |s| {
20469                                s.select_ranges(ranges);
20470                            },
20471                        );
20472                        editor.nav_history = nav_history;
20473                    });
20474                }
20475            })
20476        });
20477    }
20478
20479    // For now, don't allow opening excerpts in buffers that aren't backed by
20480    // regular project files.
20481    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20482        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20483    }
20484
20485    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20486        let snapshot = self.buffer.read(cx).read(cx);
20487        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20488        Some(
20489            ranges
20490                .iter()
20491                .map(move |range| {
20492                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20493                })
20494                .collect(),
20495        )
20496    }
20497
20498    fn selection_replacement_ranges(
20499        &self,
20500        range: Range<OffsetUtf16>,
20501        cx: &mut App,
20502    ) -> Vec<Range<OffsetUtf16>> {
20503        let selections = self.selections.all::<OffsetUtf16>(cx);
20504        let newest_selection = selections
20505            .iter()
20506            .max_by_key(|selection| selection.id)
20507            .unwrap();
20508        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20509        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20510        let snapshot = self.buffer.read(cx).read(cx);
20511        selections
20512            .into_iter()
20513            .map(|mut selection| {
20514                selection.start.0 =
20515                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20516                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20517                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20518                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20519            })
20520            .collect()
20521    }
20522
20523    fn report_editor_event(
20524        &self,
20525        reported_event: ReportEditorEvent,
20526        file_extension: Option<String>,
20527        cx: &App,
20528    ) {
20529        if cfg!(any(test, feature = "test-support")) {
20530            return;
20531        }
20532
20533        let Some(project) = &self.project else { return };
20534
20535        // If None, we are in a file without an extension
20536        let file = self
20537            .buffer
20538            .read(cx)
20539            .as_singleton()
20540            .and_then(|b| b.read(cx).file());
20541        let file_extension = file_extension.or(file
20542            .as_ref()
20543            .and_then(|file| Path::new(file.file_name(cx)).extension())
20544            .and_then(|e| e.to_str())
20545            .map(|a| a.to_string()));
20546
20547        let vim_mode = vim_enabled(cx);
20548
20549        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20550        let copilot_enabled = edit_predictions_provider
20551            == language::language_settings::EditPredictionProvider::Copilot;
20552        let copilot_enabled_for_language = self
20553            .buffer
20554            .read(cx)
20555            .language_settings(cx)
20556            .show_edit_predictions;
20557
20558        let project = project.read(cx);
20559        let event_type = reported_event.event_type();
20560
20561        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20562            telemetry::event!(
20563                event_type,
20564                type = if auto_saved {"autosave"} else {"manual"},
20565                file_extension,
20566                vim_mode,
20567                copilot_enabled,
20568                copilot_enabled_for_language,
20569                edit_predictions_provider,
20570                is_via_ssh = project.is_via_ssh(),
20571            );
20572        } else {
20573            telemetry::event!(
20574                event_type,
20575                file_extension,
20576                vim_mode,
20577                copilot_enabled,
20578                copilot_enabled_for_language,
20579                edit_predictions_provider,
20580                is_via_ssh = project.is_via_ssh(),
20581            );
20582        };
20583    }
20584
20585    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20586    /// with each line being an array of {text, highlight} objects.
20587    fn copy_highlight_json(
20588        &mut self,
20589        _: &CopyHighlightJson,
20590        window: &mut Window,
20591        cx: &mut Context<Self>,
20592    ) {
20593        #[derive(Serialize)]
20594        struct Chunk<'a> {
20595            text: String,
20596            highlight: Option<&'a str>,
20597        }
20598
20599        let snapshot = self.buffer.read(cx).snapshot(cx);
20600        let range = self
20601            .selected_text_range(false, window, cx)
20602            .and_then(|selection| {
20603                if selection.range.is_empty() {
20604                    None
20605                } else {
20606                    Some(selection.range)
20607                }
20608            })
20609            .unwrap_or_else(|| 0..snapshot.len());
20610
20611        let chunks = snapshot.chunks(range, true);
20612        let mut lines = Vec::new();
20613        let mut line: VecDeque<Chunk> = VecDeque::new();
20614
20615        let Some(style) = self.style.as_ref() else {
20616            return;
20617        };
20618
20619        for chunk in chunks {
20620            let highlight = chunk
20621                .syntax_highlight_id
20622                .and_then(|id| id.name(&style.syntax));
20623            let mut chunk_lines = chunk.text.split('\n').peekable();
20624            while let Some(text) = chunk_lines.next() {
20625                let mut merged_with_last_token = false;
20626                if let Some(last_token) = line.back_mut()
20627                    && last_token.highlight == highlight
20628                {
20629                    last_token.text.push_str(text);
20630                    merged_with_last_token = true;
20631                }
20632
20633                if !merged_with_last_token {
20634                    line.push_back(Chunk {
20635                        text: text.into(),
20636                        highlight,
20637                    });
20638                }
20639
20640                if chunk_lines.peek().is_some() {
20641                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20642                        line.pop_front();
20643                    }
20644                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20645                        line.pop_back();
20646                    }
20647
20648                    lines.push(mem::take(&mut line));
20649                }
20650            }
20651        }
20652
20653        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20654            return;
20655        };
20656        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20657    }
20658
20659    pub fn open_context_menu(
20660        &mut self,
20661        _: &OpenContextMenu,
20662        window: &mut Window,
20663        cx: &mut Context<Self>,
20664    ) {
20665        self.request_autoscroll(Autoscroll::newest(), cx);
20666        let position = self.selections.newest_display(cx).start;
20667        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20668    }
20669
20670    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20671        &self.inlay_hint_cache
20672    }
20673
20674    pub fn replay_insert_event(
20675        &mut self,
20676        text: &str,
20677        relative_utf16_range: Option<Range<isize>>,
20678        window: &mut Window,
20679        cx: &mut Context<Self>,
20680    ) {
20681        if !self.input_enabled {
20682            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20683            return;
20684        }
20685        if let Some(relative_utf16_range) = relative_utf16_range {
20686            let selections = self.selections.all::<OffsetUtf16>(cx);
20687            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20688                let new_ranges = selections.into_iter().map(|range| {
20689                    let start = OffsetUtf16(
20690                        range
20691                            .head()
20692                            .0
20693                            .saturating_add_signed(relative_utf16_range.start),
20694                    );
20695                    let end = OffsetUtf16(
20696                        range
20697                            .head()
20698                            .0
20699                            .saturating_add_signed(relative_utf16_range.end),
20700                    );
20701                    start..end
20702                });
20703                s.select_ranges(new_ranges);
20704            });
20705        }
20706
20707        self.handle_input(text, window, cx);
20708    }
20709
20710    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20711        let Some(provider) = self.semantics_provider.as_ref() else {
20712            return false;
20713        };
20714
20715        let mut supports = false;
20716        self.buffer().update(cx, |this, cx| {
20717            this.for_each_buffer(|buffer| {
20718                supports |= provider.supports_inlay_hints(buffer, cx);
20719            });
20720        });
20721
20722        supports
20723    }
20724
20725    pub fn is_focused(&self, window: &Window) -> bool {
20726        self.focus_handle.is_focused(window)
20727    }
20728
20729    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20730        cx.emit(EditorEvent::Focused);
20731
20732        if let Some(descendant) = self
20733            .last_focused_descendant
20734            .take()
20735            .and_then(|descendant| descendant.upgrade())
20736        {
20737            window.focus(&descendant);
20738        } else {
20739            if let Some(blame) = self.blame.as_ref() {
20740                blame.update(cx, GitBlame::focus)
20741            }
20742
20743            self.blink_manager.update(cx, BlinkManager::enable);
20744            self.show_cursor_names(window, cx);
20745            self.buffer.update(cx, |buffer, cx| {
20746                buffer.finalize_last_transaction(cx);
20747                if self.leader_id.is_none() {
20748                    buffer.set_active_selections(
20749                        &self.selections.disjoint_anchors(),
20750                        self.selections.line_mode,
20751                        self.cursor_shape,
20752                        cx,
20753                    );
20754                }
20755            });
20756        }
20757    }
20758
20759    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20760        cx.emit(EditorEvent::FocusedIn)
20761    }
20762
20763    fn handle_focus_out(
20764        &mut self,
20765        event: FocusOutEvent,
20766        _window: &mut Window,
20767        cx: &mut Context<Self>,
20768    ) {
20769        if event.blurred != self.focus_handle {
20770            self.last_focused_descendant = Some(event.blurred);
20771        }
20772        self.selection_drag_state = SelectionDragState::None;
20773        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20774    }
20775
20776    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20777        self.blink_manager.update(cx, BlinkManager::disable);
20778        self.buffer
20779            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20780
20781        if let Some(blame) = self.blame.as_ref() {
20782            blame.update(cx, GitBlame::blur)
20783        }
20784        if !self.hover_state.focused(window, cx) {
20785            hide_hover(self, cx);
20786        }
20787        if !self
20788            .context_menu
20789            .borrow()
20790            .as_ref()
20791            .is_some_and(|context_menu| context_menu.focused(window, cx))
20792        {
20793            self.hide_context_menu(window, cx);
20794        }
20795        self.discard_edit_prediction(false, cx);
20796        cx.emit(EditorEvent::Blurred);
20797        cx.notify();
20798    }
20799
20800    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20801        let mut pending: String = window
20802            .pending_input_keystrokes()
20803            .into_iter()
20804            .flatten()
20805            .filter_map(|keystroke| {
20806                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20807                    keystroke.key_char.clone()
20808                } else {
20809                    None
20810                }
20811            })
20812            .collect();
20813
20814        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20815            pending = "".to_string();
20816        }
20817
20818        let existing_pending = self
20819            .text_highlights::<PendingInput>(cx)
20820            .map(|(_, ranges)| ranges.to_vec());
20821        if existing_pending.is_none() && pending.is_empty() {
20822            return;
20823        }
20824        let transaction =
20825            self.transact(window, cx, |this, window, cx| {
20826                let selections = this.selections.all::<usize>(cx);
20827                let edits = selections
20828                    .iter()
20829                    .map(|selection| (selection.end..selection.end, pending.clone()));
20830                this.edit(edits, cx);
20831                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20832                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20833                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20834                    }));
20835                });
20836                if let Some(existing_ranges) = existing_pending {
20837                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20838                    this.edit(edits, cx);
20839                }
20840            });
20841
20842        let snapshot = self.snapshot(window, cx);
20843        let ranges = self
20844            .selections
20845            .all::<usize>(cx)
20846            .into_iter()
20847            .map(|selection| {
20848                snapshot.buffer_snapshot.anchor_after(selection.end)
20849                    ..snapshot
20850                        .buffer_snapshot
20851                        .anchor_before(selection.end + pending.len())
20852            })
20853            .collect();
20854
20855        if pending.is_empty() {
20856            self.clear_highlights::<PendingInput>(cx);
20857        } else {
20858            self.highlight_text::<PendingInput>(
20859                ranges,
20860                HighlightStyle {
20861                    underline: Some(UnderlineStyle {
20862                        thickness: px(1.),
20863                        color: None,
20864                        wavy: false,
20865                    }),
20866                    ..Default::default()
20867                },
20868                cx,
20869            );
20870        }
20871
20872        self.ime_transaction = self.ime_transaction.or(transaction);
20873        if let Some(transaction) = self.ime_transaction {
20874            self.buffer.update(cx, |buffer, cx| {
20875                buffer.group_until_transaction(transaction, cx);
20876            });
20877        }
20878
20879        if self.text_highlights::<PendingInput>(cx).is_none() {
20880            self.ime_transaction.take();
20881        }
20882    }
20883
20884    pub fn register_action_renderer(
20885        &mut self,
20886        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20887    ) -> Subscription {
20888        let id = self.next_editor_action_id.post_inc();
20889        self.editor_actions
20890            .borrow_mut()
20891            .insert(id, Box::new(listener));
20892
20893        let editor_actions = self.editor_actions.clone();
20894        Subscription::new(move || {
20895            editor_actions.borrow_mut().remove(&id);
20896        })
20897    }
20898
20899    pub fn register_action<A: Action>(
20900        &mut self,
20901        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20902    ) -> Subscription {
20903        let id = self.next_editor_action_id.post_inc();
20904        let listener = Arc::new(listener);
20905        self.editor_actions.borrow_mut().insert(
20906            id,
20907            Box::new(move |_, window, _| {
20908                let listener = listener.clone();
20909                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20910                    let action = action.downcast_ref().unwrap();
20911                    if phase == DispatchPhase::Bubble {
20912                        listener(action, window, cx)
20913                    }
20914                })
20915            }),
20916        );
20917
20918        let editor_actions = self.editor_actions.clone();
20919        Subscription::new(move || {
20920            editor_actions.borrow_mut().remove(&id);
20921        })
20922    }
20923
20924    pub fn file_header_size(&self) -> u32 {
20925        FILE_HEADER_HEIGHT
20926    }
20927
20928    pub fn restore(
20929        &mut self,
20930        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20931        window: &mut Window,
20932        cx: &mut Context<Self>,
20933    ) {
20934        let workspace = self.workspace();
20935        let project = self.project();
20936        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20937            let mut tasks = Vec::new();
20938            for (buffer_id, changes) in revert_changes {
20939                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20940                    buffer.update(cx, |buffer, cx| {
20941                        buffer.edit(
20942                            changes
20943                                .into_iter()
20944                                .map(|(range, text)| (range, text.to_string())),
20945                            None,
20946                            cx,
20947                        );
20948                    });
20949
20950                    if let Some(project) =
20951                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20952                    {
20953                        project.update(cx, |project, cx| {
20954                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20955                        })
20956                    }
20957                }
20958            }
20959            tasks
20960        });
20961        cx.spawn_in(window, async move |_, cx| {
20962            for (buffer, task) in save_tasks {
20963                let result = task.await;
20964                if result.is_err() {
20965                    let Some(path) = buffer
20966                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20967                        .ok()
20968                    else {
20969                        continue;
20970                    };
20971                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20972                        let Some(task) = cx
20973                            .update_window_entity(workspace, |workspace, window, cx| {
20974                                workspace
20975                                    .open_path_preview(path, None, false, false, false, window, cx)
20976                            })
20977                            .ok()
20978                        else {
20979                            continue;
20980                        };
20981                        task.await.log_err();
20982                    }
20983                }
20984            }
20985        })
20986        .detach();
20987        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20988            selections.refresh()
20989        });
20990    }
20991
20992    pub fn to_pixel_point(
20993        &self,
20994        source: multi_buffer::Anchor,
20995        editor_snapshot: &EditorSnapshot,
20996        window: &mut Window,
20997    ) -> Option<gpui::Point<Pixels>> {
20998        let source_point = source.to_display_point(editor_snapshot);
20999        self.display_to_pixel_point(source_point, editor_snapshot, window)
21000    }
21001
21002    pub fn display_to_pixel_point(
21003        &self,
21004        source: DisplayPoint,
21005        editor_snapshot: &EditorSnapshot,
21006        window: &mut Window,
21007    ) -> Option<gpui::Point<Pixels>> {
21008        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21009        let text_layout_details = self.text_layout_details(window);
21010        let scroll_top = text_layout_details
21011            .scroll_anchor
21012            .scroll_position(editor_snapshot)
21013            .y;
21014
21015        if source.row().as_f32() < scroll_top.floor() {
21016            return None;
21017        }
21018        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21019        let source_y = line_height * (source.row().as_f32() - scroll_top);
21020        Some(gpui::Point::new(source_x, source_y))
21021    }
21022
21023    pub fn has_visible_completions_menu(&self) -> bool {
21024        !self.edit_prediction_preview_is_active()
21025            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21026                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21027            })
21028    }
21029
21030    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21031        if self.mode.is_minimap() {
21032            return;
21033        }
21034        self.addons
21035            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21036    }
21037
21038    pub fn unregister_addon<T: Addon>(&mut self) {
21039        self.addons.remove(&std::any::TypeId::of::<T>());
21040    }
21041
21042    pub fn addon<T: Addon>(&self) -> Option<&T> {
21043        let type_id = std::any::TypeId::of::<T>();
21044        self.addons
21045            .get(&type_id)
21046            .and_then(|item| item.to_any().downcast_ref::<T>())
21047    }
21048
21049    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21050        let type_id = std::any::TypeId::of::<T>();
21051        self.addons
21052            .get_mut(&type_id)
21053            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21054    }
21055
21056    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21057        let text_layout_details = self.text_layout_details(window);
21058        let style = &text_layout_details.editor_style;
21059        let font_id = window.text_system().resolve_font(&style.text.font());
21060        let font_size = style.text.font_size.to_pixels(window.rem_size());
21061        let line_height = style.text.line_height_in_pixels(window.rem_size());
21062        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21063        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21064
21065        CharacterDimensions {
21066            em_width,
21067            em_advance,
21068            line_height,
21069        }
21070    }
21071
21072    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21073        self.load_diff_task.clone()
21074    }
21075
21076    fn read_metadata_from_db(
21077        &mut self,
21078        item_id: u64,
21079        workspace_id: WorkspaceId,
21080        window: &mut Window,
21081        cx: &mut Context<Editor>,
21082    ) {
21083        if self.is_singleton(cx)
21084            && !self.mode.is_minimap()
21085            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21086        {
21087            let buffer_snapshot = OnceCell::new();
21088
21089            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21090                && !folds.is_empty()
21091            {
21092                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21093                self.fold_ranges(
21094                    folds
21095                        .into_iter()
21096                        .map(|(start, end)| {
21097                            snapshot.clip_offset(start, Bias::Left)
21098                                ..snapshot.clip_offset(end, Bias::Right)
21099                        })
21100                        .collect(),
21101                    false,
21102                    window,
21103                    cx,
21104                );
21105            }
21106
21107            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21108                && !selections.is_empty()
21109            {
21110                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21111                // skip adding the initial selection to selection history
21112                self.selection_history.mode = SelectionHistoryMode::Skipping;
21113                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21114                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21115                        snapshot.clip_offset(start, Bias::Left)
21116                            ..snapshot.clip_offset(end, Bias::Right)
21117                    }));
21118                });
21119                self.selection_history.mode = SelectionHistoryMode::Normal;
21120            };
21121        }
21122
21123        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21124    }
21125
21126    fn update_lsp_data(
21127        &mut self,
21128        ignore_cache: bool,
21129        for_buffer: Option<BufferId>,
21130        window: &mut Window,
21131        cx: &mut Context<'_, Self>,
21132    ) {
21133        self.pull_diagnostics(for_buffer, window, cx);
21134        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21135    }
21136}
21137
21138fn vim_enabled(cx: &App) -> bool {
21139    cx.global::<SettingsStore>()
21140        .raw_user_settings()
21141        .get("vim_mode")
21142        == Some(&serde_json::Value::Bool(true))
21143}
21144
21145fn process_completion_for_edit(
21146    completion: &Completion,
21147    intent: CompletionIntent,
21148    buffer: &Entity<Buffer>,
21149    cursor_position: &text::Anchor,
21150    cx: &mut Context<Editor>,
21151) -> CompletionEdit {
21152    let buffer = buffer.read(cx);
21153    let buffer_snapshot = buffer.snapshot();
21154    let (snippet, new_text) = if completion.is_snippet() {
21155        // Workaround for typescript language server issues so that methods don't expand within
21156        // strings and functions with type expressions. The previous point is used because the query
21157        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21158        let mut snippet_source = completion.new_text.clone();
21159        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21160        previous_point.column = previous_point.column.saturating_sub(1);
21161        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21162            && scope.prefers_label_for_snippet_in_completion()
21163            && let Some(label) = completion.label()
21164            && matches!(
21165                completion.kind(),
21166                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21167            )
21168        {
21169            snippet_source = label;
21170        }
21171        match Snippet::parse(&snippet_source).log_err() {
21172            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21173            None => (None, completion.new_text.clone()),
21174        }
21175    } else {
21176        (None, completion.new_text.clone())
21177    };
21178
21179    let mut range_to_replace = {
21180        let replace_range = &completion.replace_range;
21181        if let CompletionSource::Lsp {
21182            insert_range: Some(insert_range),
21183            ..
21184        } = &completion.source
21185        {
21186            debug_assert_eq!(
21187                insert_range.start, replace_range.start,
21188                "insert_range and replace_range should start at the same position"
21189            );
21190            debug_assert!(
21191                insert_range
21192                    .start
21193                    .cmp(cursor_position, &buffer_snapshot)
21194                    .is_le(),
21195                "insert_range should start before or at cursor position"
21196            );
21197            debug_assert!(
21198                replace_range
21199                    .start
21200                    .cmp(cursor_position, &buffer_snapshot)
21201                    .is_le(),
21202                "replace_range should start before or at cursor position"
21203            );
21204
21205            let should_replace = match intent {
21206                CompletionIntent::CompleteWithInsert => false,
21207                CompletionIntent::CompleteWithReplace => true,
21208                CompletionIntent::Complete | CompletionIntent::Compose => {
21209                    let insert_mode =
21210                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21211                            .completions
21212                            .lsp_insert_mode;
21213                    match insert_mode {
21214                        LspInsertMode::Insert => false,
21215                        LspInsertMode::Replace => true,
21216                        LspInsertMode::ReplaceSubsequence => {
21217                            let mut text_to_replace = buffer.chars_for_range(
21218                                buffer.anchor_before(replace_range.start)
21219                                    ..buffer.anchor_after(replace_range.end),
21220                            );
21221                            let mut current_needle = text_to_replace.next();
21222                            for haystack_ch in completion.label.text.chars() {
21223                                if let Some(needle_ch) = current_needle
21224                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21225                                {
21226                                    current_needle = text_to_replace.next();
21227                                }
21228                            }
21229                            current_needle.is_none()
21230                        }
21231                        LspInsertMode::ReplaceSuffix => {
21232                            if replace_range
21233                                .end
21234                                .cmp(cursor_position, &buffer_snapshot)
21235                                .is_gt()
21236                            {
21237                                let range_after_cursor = *cursor_position..replace_range.end;
21238                                let text_after_cursor = buffer
21239                                    .text_for_range(
21240                                        buffer.anchor_before(range_after_cursor.start)
21241                                            ..buffer.anchor_after(range_after_cursor.end),
21242                                    )
21243                                    .collect::<String>()
21244                                    .to_ascii_lowercase();
21245                                completion
21246                                    .label
21247                                    .text
21248                                    .to_ascii_lowercase()
21249                                    .ends_with(&text_after_cursor)
21250                            } else {
21251                                true
21252                            }
21253                        }
21254                    }
21255                }
21256            };
21257
21258            if should_replace {
21259                replace_range.clone()
21260            } else {
21261                insert_range.clone()
21262            }
21263        } else {
21264            replace_range.clone()
21265        }
21266    };
21267
21268    if range_to_replace
21269        .end
21270        .cmp(cursor_position, &buffer_snapshot)
21271        .is_lt()
21272    {
21273        range_to_replace.end = *cursor_position;
21274    }
21275
21276    CompletionEdit {
21277        new_text,
21278        replace_range: range_to_replace.to_offset(buffer),
21279        snippet,
21280    }
21281}
21282
21283struct CompletionEdit {
21284    new_text: String,
21285    replace_range: Range<usize>,
21286    snippet: Option<Snippet>,
21287}
21288
21289fn insert_extra_newline_brackets(
21290    buffer: &MultiBufferSnapshot,
21291    range: Range<usize>,
21292    language: &language::LanguageScope,
21293) -> bool {
21294    let leading_whitespace_len = buffer
21295        .reversed_chars_at(range.start)
21296        .take_while(|c| c.is_whitespace() && *c != '\n')
21297        .map(|c| c.len_utf8())
21298        .sum::<usize>();
21299    let trailing_whitespace_len = buffer
21300        .chars_at(range.end)
21301        .take_while(|c| c.is_whitespace() && *c != '\n')
21302        .map(|c| c.len_utf8())
21303        .sum::<usize>();
21304    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21305
21306    language.brackets().any(|(pair, enabled)| {
21307        let pair_start = pair.start.trim_end();
21308        let pair_end = pair.end.trim_start();
21309
21310        enabled
21311            && pair.newline
21312            && buffer.contains_str_at(range.end, pair_end)
21313            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21314    })
21315}
21316
21317fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21318    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21319        [(buffer, range, _)] => (*buffer, range.clone()),
21320        _ => return false,
21321    };
21322    let pair = {
21323        let mut result: Option<BracketMatch> = None;
21324
21325        for pair in buffer
21326            .all_bracket_ranges(range.clone())
21327            .filter(move |pair| {
21328                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21329            })
21330        {
21331            let len = pair.close_range.end - pair.open_range.start;
21332
21333            if let Some(existing) = &result {
21334                let existing_len = existing.close_range.end - existing.open_range.start;
21335                if len > existing_len {
21336                    continue;
21337                }
21338            }
21339
21340            result = Some(pair);
21341        }
21342
21343        result
21344    };
21345    let Some(pair) = pair else {
21346        return false;
21347    };
21348    pair.newline_only
21349        && buffer
21350            .chars_for_range(pair.open_range.end..range.start)
21351            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21352            .all(|c| c.is_whitespace() && c != '\n')
21353}
21354
21355fn update_uncommitted_diff_for_buffer(
21356    editor: Entity<Editor>,
21357    project: &Entity<Project>,
21358    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21359    buffer: Entity<MultiBuffer>,
21360    cx: &mut App,
21361) -> Task<()> {
21362    let mut tasks = Vec::new();
21363    project.update(cx, |project, cx| {
21364        for buffer in buffers {
21365            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21366                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21367            }
21368        }
21369    });
21370    cx.spawn(async move |cx| {
21371        let diffs = future::join_all(tasks).await;
21372        if editor
21373            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21374            .unwrap_or(false)
21375        {
21376            return;
21377        }
21378
21379        buffer
21380            .update(cx, |buffer, cx| {
21381                for diff in diffs.into_iter().flatten() {
21382                    buffer.add_diff(diff, cx);
21383                }
21384            })
21385            .ok();
21386    })
21387}
21388
21389fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21390    let tab_size = tab_size.get() as usize;
21391    let mut width = offset;
21392
21393    for ch in text.chars() {
21394        width += if ch == '\t' {
21395            tab_size - (width % tab_size)
21396        } else {
21397            1
21398        };
21399    }
21400
21401    width - offset
21402}
21403
21404#[cfg(test)]
21405mod tests {
21406    use super::*;
21407
21408    #[test]
21409    fn test_string_size_with_expanded_tabs() {
21410        let nz = |val| NonZeroU32::new(val).unwrap();
21411        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21412        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21413        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21414        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21415        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21416        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21417        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21418        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21419    }
21420}
21421
21422/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21423struct WordBreakingTokenizer<'a> {
21424    input: &'a str,
21425}
21426
21427impl<'a> WordBreakingTokenizer<'a> {
21428    fn new(input: &'a str) -> Self {
21429        Self { input }
21430    }
21431}
21432
21433fn is_char_ideographic(ch: char) -> bool {
21434    use unicode_script::Script::*;
21435    use unicode_script::UnicodeScript;
21436    matches!(ch.script(), Han | Tangut | Yi)
21437}
21438
21439fn is_grapheme_ideographic(text: &str) -> bool {
21440    text.chars().any(is_char_ideographic)
21441}
21442
21443fn is_grapheme_whitespace(text: &str) -> bool {
21444    text.chars().any(|x| x.is_whitespace())
21445}
21446
21447fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21448    text.chars()
21449        .next()
21450        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21451}
21452
21453#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21454enum WordBreakToken<'a> {
21455    Word { token: &'a str, grapheme_len: usize },
21456    InlineWhitespace { token: &'a str, grapheme_len: usize },
21457    Newline,
21458}
21459
21460impl<'a> Iterator for WordBreakingTokenizer<'a> {
21461    /// Yields a span, the count of graphemes in the token, and whether it was
21462    /// whitespace. Note that it also breaks at word boundaries.
21463    type Item = WordBreakToken<'a>;
21464
21465    fn next(&mut self) -> Option<Self::Item> {
21466        use unicode_segmentation::UnicodeSegmentation;
21467        if self.input.is_empty() {
21468            return None;
21469        }
21470
21471        let mut iter = self.input.graphemes(true).peekable();
21472        let mut offset = 0;
21473        let mut grapheme_len = 0;
21474        if let Some(first_grapheme) = iter.next() {
21475            let is_newline = first_grapheme == "\n";
21476            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21477            offset += first_grapheme.len();
21478            grapheme_len += 1;
21479            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21480                if let Some(grapheme) = iter.peek().copied()
21481                    && should_stay_with_preceding_ideograph(grapheme)
21482                {
21483                    offset += grapheme.len();
21484                    grapheme_len += 1;
21485                }
21486            } else {
21487                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21488                let mut next_word_bound = words.peek().copied();
21489                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21490                    next_word_bound = words.next();
21491                }
21492                while let Some(grapheme) = iter.peek().copied() {
21493                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21494                        break;
21495                    };
21496                    if is_grapheme_whitespace(grapheme) != is_whitespace
21497                        || (grapheme == "\n") != is_newline
21498                    {
21499                        break;
21500                    };
21501                    offset += grapheme.len();
21502                    grapheme_len += 1;
21503                    iter.next();
21504                }
21505            }
21506            let token = &self.input[..offset];
21507            self.input = &self.input[offset..];
21508            if token == "\n" {
21509                Some(WordBreakToken::Newline)
21510            } else if is_whitespace {
21511                Some(WordBreakToken::InlineWhitespace {
21512                    token,
21513                    grapheme_len,
21514                })
21515            } else {
21516                Some(WordBreakToken::Word {
21517                    token,
21518                    grapheme_len,
21519                })
21520            }
21521        } else {
21522            None
21523        }
21524    }
21525}
21526
21527#[test]
21528fn test_word_breaking_tokenizer() {
21529    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21530        ("", &[]),
21531        ("  ", &[whitespace("  ", 2)]),
21532        ("Ʒ", &[word("Ʒ", 1)]),
21533        ("Ǽ", &[word("Ǽ", 1)]),
21534        ("", &[word("", 1)]),
21535        ("⋑⋑", &[word("⋑⋑", 2)]),
21536        (
21537            "原理,进而",
21538            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21539        ),
21540        (
21541            "hello world",
21542            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21543        ),
21544        (
21545            "hello, world",
21546            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21547        ),
21548        (
21549            "  hello world",
21550            &[
21551                whitespace("  ", 2),
21552                word("hello", 5),
21553                whitespace(" ", 1),
21554                word("world", 5),
21555            ],
21556        ),
21557        (
21558            "这是什么 \n 钢笔",
21559            &[
21560                word("", 1),
21561                word("", 1),
21562                word("", 1),
21563                word("", 1),
21564                whitespace(" ", 1),
21565                newline(),
21566                whitespace(" ", 1),
21567                word("", 1),
21568                word("", 1),
21569            ],
21570        ),
21571        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21572    ];
21573
21574    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21575        WordBreakToken::Word {
21576            token,
21577            grapheme_len,
21578        }
21579    }
21580
21581    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21582        WordBreakToken::InlineWhitespace {
21583            token,
21584            grapheme_len,
21585        }
21586    }
21587
21588    fn newline() -> WordBreakToken<'static> {
21589        WordBreakToken::Newline
21590    }
21591
21592    for (input, result) in tests {
21593        assert_eq!(
21594            WordBreakingTokenizer::new(input)
21595                .collect::<Vec<_>>()
21596                .as_slice(),
21597            *result,
21598        );
21599    }
21600}
21601
21602fn wrap_with_prefix(
21603    first_line_prefix: String,
21604    subsequent_lines_prefix: String,
21605    unwrapped_text: String,
21606    wrap_column: usize,
21607    tab_size: NonZeroU32,
21608    preserve_existing_whitespace: bool,
21609) -> String {
21610    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21611    let subsequent_lines_prefix_len =
21612        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21613    let mut wrapped_text = String::new();
21614    let mut current_line = first_line_prefix;
21615    let mut is_first_line = true;
21616
21617    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21618    let mut current_line_len = first_line_prefix_len;
21619    let mut in_whitespace = false;
21620    for token in tokenizer {
21621        let have_preceding_whitespace = in_whitespace;
21622        match token {
21623            WordBreakToken::Word {
21624                token,
21625                grapheme_len,
21626            } => {
21627                in_whitespace = false;
21628                let current_prefix_len = if is_first_line {
21629                    first_line_prefix_len
21630                } else {
21631                    subsequent_lines_prefix_len
21632                };
21633                if current_line_len + grapheme_len > wrap_column
21634                    && current_line_len != current_prefix_len
21635                {
21636                    wrapped_text.push_str(current_line.trim_end());
21637                    wrapped_text.push('\n');
21638                    is_first_line = false;
21639                    current_line = subsequent_lines_prefix.clone();
21640                    current_line_len = subsequent_lines_prefix_len;
21641                }
21642                current_line.push_str(token);
21643                current_line_len += grapheme_len;
21644            }
21645            WordBreakToken::InlineWhitespace {
21646                mut token,
21647                mut grapheme_len,
21648            } => {
21649                in_whitespace = true;
21650                if have_preceding_whitespace && !preserve_existing_whitespace {
21651                    continue;
21652                }
21653                if !preserve_existing_whitespace {
21654                    token = " ";
21655                    grapheme_len = 1;
21656                }
21657                let current_prefix_len = if is_first_line {
21658                    first_line_prefix_len
21659                } else {
21660                    subsequent_lines_prefix_len
21661                };
21662                if current_line_len + grapheme_len > wrap_column {
21663                    wrapped_text.push_str(current_line.trim_end());
21664                    wrapped_text.push('\n');
21665                    is_first_line = false;
21666                    current_line = subsequent_lines_prefix.clone();
21667                    current_line_len = subsequent_lines_prefix_len;
21668                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21669                    current_line.push_str(token);
21670                    current_line_len += grapheme_len;
21671                }
21672            }
21673            WordBreakToken::Newline => {
21674                in_whitespace = true;
21675                let current_prefix_len = if is_first_line {
21676                    first_line_prefix_len
21677                } else {
21678                    subsequent_lines_prefix_len
21679                };
21680                if preserve_existing_whitespace {
21681                    wrapped_text.push_str(current_line.trim_end());
21682                    wrapped_text.push('\n');
21683                    is_first_line = false;
21684                    current_line = subsequent_lines_prefix.clone();
21685                    current_line_len = subsequent_lines_prefix_len;
21686                } else if have_preceding_whitespace {
21687                    continue;
21688                } else if current_line_len + 1 > wrap_column
21689                    && current_line_len != current_prefix_len
21690                {
21691                    wrapped_text.push_str(current_line.trim_end());
21692                    wrapped_text.push('\n');
21693                    is_first_line = false;
21694                    current_line = subsequent_lines_prefix.clone();
21695                    current_line_len = subsequent_lines_prefix_len;
21696                } else if current_line_len != current_prefix_len {
21697                    current_line.push(' ');
21698                    current_line_len += 1;
21699                }
21700            }
21701        }
21702    }
21703
21704    if !current_line.is_empty() {
21705        wrapped_text.push_str(&current_line);
21706    }
21707    wrapped_text
21708}
21709
21710#[test]
21711fn test_wrap_with_prefix() {
21712    assert_eq!(
21713        wrap_with_prefix(
21714            "# ".to_string(),
21715            "# ".to_string(),
21716            "abcdefg".to_string(),
21717            4,
21718            NonZeroU32::new(4).unwrap(),
21719            false,
21720        ),
21721        "# abcdefg"
21722    );
21723    assert_eq!(
21724        wrap_with_prefix(
21725            "".to_string(),
21726            "".to_string(),
21727            "\thello world".to_string(),
21728            8,
21729            NonZeroU32::new(4).unwrap(),
21730            false,
21731        ),
21732        "hello\nworld"
21733    );
21734    assert_eq!(
21735        wrap_with_prefix(
21736            "// ".to_string(),
21737            "// ".to_string(),
21738            "xx \nyy zz aa bb cc".to_string(),
21739            12,
21740            NonZeroU32::new(4).unwrap(),
21741            false,
21742        ),
21743        "// xx yy zz\n// aa bb cc"
21744    );
21745    assert_eq!(
21746        wrap_with_prefix(
21747            String::new(),
21748            String::new(),
21749            "这是什么 \n 钢笔".to_string(),
21750            3,
21751            NonZeroU32::new(4).unwrap(),
21752            false,
21753        ),
21754        "这是什\n么 钢\n"
21755    );
21756}
21757
21758pub trait CollaborationHub {
21759    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21760    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21761    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21762}
21763
21764impl CollaborationHub for Entity<Project> {
21765    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21766        self.read(cx).collaborators()
21767    }
21768
21769    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21770        self.read(cx).user_store().read(cx).participant_indices()
21771    }
21772
21773    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21774        let this = self.read(cx);
21775        let user_ids = this.collaborators().values().map(|c| c.user_id);
21776        this.user_store().read(cx).participant_names(user_ids, cx)
21777    }
21778}
21779
21780pub trait SemanticsProvider {
21781    fn hover(
21782        &self,
21783        buffer: &Entity<Buffer>,
21784        position: text::Anchor,
21785        cx: &mut App,
21786    ) -> Option<Task<Vec<project::Hover>>>;
21787
21788    fn inline_values(
21789        &self,
21790        buffer_handle: Entity<Buffer>,
21791        range: Range<text::Anchor>,
21792        cx: &mut App,
21793    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21794
21795    fn inlay_hints(
21796        &self,
21797        buffer_handle: Entity<Buffer>,
21798        range: Range<text::Anchor>,
21799        cx: &mut App,
21800    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21801
21802    fn resolve_inlay_hint(
21803        &self,
21804        hint: InlayHint,
21805        buffer_handle: Entity<Buffer>,
21806        server_id: LanguageServerId,
21807        cx: &mut App,
21808    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21809
21810    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21811
21812    fn document_highlights(
21813        &self,
21814        buffer: &Entity<Buffer>,
21815        position: text::Anchor,
21816        cx: &mut App,
21817    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21818
21819    fn definitions(
21820        &self,
21821        buffer: &Entity<Buffer>,
21822        position: text::Anchor,
21823        kind: GotoDefinitionKind,
21824        cx: &mut App,
21825    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21826
21827    fn range_for_rename(
21828        &self,
21829        buffer: &Entity<Buffer>,
21830        position: text::Anchor,
21831        cx: &mut App,
21832    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21833
21834    fn perform_rename(
21835        &self,
21836        buffer: &Entity<Buffer>,
21837        position: text::Anchor,
21838        new_name: String,
21839        cx: &mut App,
21840    ) -> Option<Task<Result<ProjectTransaction>>>;
21841}
21842
21843pub trait CompletionProvider {
21844    fn completions(
21845        &self,
21846        excerpt_id: ExcerptId,
21847        buffer: &Entity<Buffer>,
21848        buffer_position: text::Anchor,
21849        trigger: CompletionContext,
21850        window: &mut Window,
21851        cx: &mut Context<Editor>,
21852    ) -> Task<Result<Vec<CompletionResponse>>>;
21853
21854    fn resolve_completions(
21855        &self,
21856        _buffer: Entity<Buffer>,
21857        _completion_indices: Vec<usize>,
21858        _completions: Rc<RefCell<Box<[Completion]>>>,
21859        _cx: &mut Context<Editor>,
21860    ) -> Task<Result<bool>> {
21861        Task::ready(Ok(false))
21862    }
21863
21864    fn apply_additional_edits_for_completion(
21865        &self,
21866        _buffer: Entity<Buffer>,
21867        _completions: Rc<RefCell<Box<[Completion]>>>,
21868        _completion_index: usize,
21869        _push_to_history: bool,
21870        _cx: &mut Context<Editor>,
21871    ) -> Task<Result<Option<language::Transaction>>> {
21872        Task::ready(Ok(None))
21873    }
21874
21875    fn is_completion_trigger(
21876        &self,
21877        buffer: &Entity<Buffer>,
21878        position: language::Anchor,
21879        text: &str,
21880        trigger_in_words: bool,
21881        menu_is_open: bool,
21882        cx: &mut Context<Editor>,
21883    ) -> bool;
21884
21885    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21886
21887    fn sort_completions(&self) -> bool {
21888        true
21889    }
21890
21891    fn filter_completions(&self) -> bool {
21892        true
21893    }
21894}
21895
21896pub trait CodeActionProvider {
21897    fn id(&self) -> Arc<str>;
21898
21899    fn code_actions(
21900        &self,
21901        buffer: &Entity<Buffer>,
21902        range: Range<text::Anchor>,
21903        window: &mut Window,
21904        cx: &mut App,
21905    ) -> Task<Result<Vec<CodeAction>>>;
21906
21907    fn apply_code_action(
21908        &self,
21909        buffer_handle: Entity<Buffer>,
21910        action: CodeAction,
21911        excerpt_id: ExcerptId,
21912        push_to_history: bool,
21913        window: &mut Window,
21914        cx: &mut App,
21915    ) -> Task<Result<ProjectTransaction>>;
21916}
21917
21918impl CodeActionProvider for Entity<Project> {
21919    fn id(&self) -> Arc<str> {
21920        "project".into()
21921    }
21922
21923    fn code_actions(
21924        &self,
21925        buffer: &Entity<Buffer>,
21926        range: Range<text::Anchor>,
21927        _window: &mut Window,
21928        cx: &mut App,
21929    ) -> Task<Result<Vec<CodeAction>>> {
21930        self.update(cx, |project, cx| {
21931            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21932            let code_actions = project.code_actions(buffer, range, None, cx);
21933            cx.background_spawn(async move {
21934                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21935                Ok(code_lens_actions
21936                    .context("code lens fetch")?
21937                    .into_iter()
21938                    .chain(code_actions.context("code action fetch")?)
21939                    .collect())
21940            })
21941        })
21942    }
21943
21944    fn apply_code_action(
21945        &self,
21946        buffer_handle: Entity<Buffer>,
21947        action: CodeAction,
21948        _excerpt_id: ExcerptId,
21949        push_to_history: bool,
21950        _window: &mut Window,
21951        cx: &mut App,
21952    ) -> Task<Result<ProjectTransaction>> {
21953        self.update(cx, |project, cx| {
21954            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21955        })
21956    }
21957}
21958
21959fn snippet_completions(
21960    project: &Project,
21961    buffer: &Entity<Buffer>,
21962    buffer_position: text::Anchor,
21963    cx: &mut App,
21964) -> Task<Result<CompletionResponse>> {
21965    let languages = buffer.read(cx).languages_at(buffer_position);
21966    let snippet_store = project.snippets().read(cx);
21967
21968    let scopes: Vec<_> = languages
21969        .iter()
21970        .filter_map(|language| {
21971            let language_name = language.lsp_id();
21972            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21973
21974            if snippets.is_empty() {
21975                None
21976            } else {
21977                Some((language.default_scope(), snippets))
21978            }
21979        })
21980        .collect();
21981
21982    if scopes.is_empty() {
21983        return Task::ready(Ok(CompletionResponse {
21984            completions: vec![],
21985            is_incomplete: false,
21986        }));
21987    }
21988
21989    let snapshot = buffer.read(cx).text_snapshot();
21990    let chars: String = snapshot
21991        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21992        .collect();
21993    let executor = cx.background_executor().clone();
21994
21995    cx.background_spawn(async move {
21996        let mut is_incomplete = false;
21997        let mut completions: Vec<Completion> = Vec::new();
21998        for (scope, snippets) in scopes.into_iter() {
21999            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22000            let mut last_word = chars
22001                .chars()
22002                .take_while(|c| classifier.is_word(*c))
22003                .collect::<String>();
22004            last_word = last_word.chars().rev().collect();
22005
22006            if last_word.is_empty() {
22007                return Ok(CompletionResponse {
22008                    completions: vec![],
22009                    is_incomplete: true,
22010                });
22011            }
22012
22013            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22014            let to_lsp = |point: &text::Anchor| {
22015                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22016                point_to_lsp(end)
22017            };
22018            let lsp_end = to_lsp(&buffer_position);
22019
22020            let candidates = snippets
22021                .iter()
22022                .enumerate()
22023                .flat_map(|(ix, snippet)| {
22024                    snippet
22025                        .prefix
22026                        .iter()
22027                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22028                })
22029                .collect::<Vec<StringMatchCandidate>>();
22030
22031            const MAX_RESULTS: usize = 100;
22032            let mut matches = fuzzy::match_strings(
22033                &candidates,
22034                &last_word,
22035                last_word.chars().any(|c| c.is_uppercase()),
22036                true,
22037                MAX_RESULTS,
22038                &Default::default(),
22039                executor.clone(),
22040            )
22041            .await;
22042
22043            if matches.len() >= MAX_RESULTS {
22044                is_incomplete = true;
22045            }
22046
22047            // Remove all candidates where the query's start does not match the start of any word in the candidate
22048            if let Some(query_start) = last_word.chars().next() {
22049                matches.retain(|string_match| {
22050                    split_words(&string_match.string).any(|word| {
22051                        // Check that the first codepoint of the word as lowercase matches the first
22052                        // codepoint of the query as lowercase
22053                        word.chars()
22054                            .flat_map(|codepoint| codepoint.to_lowercase())
22055                            .zip(query_start.to_lowercase())
22056                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22057                    })
22058                });
22059            }
22060
22061            let matched_strings = matches
22062                .into_iter()
22063                .map(|m| m.string)
22064                .collect::<HashSet<_>>();
22065
22066            completions.extend(snippets.iter().filter_map(|snippet| {
22067                let matching_prefix = snippet
22068                    .prefix
22069                    .iter()
22070                    .find(|prefix| matched_strings.contains(*prefix))?;
22071                let start = as_offset - last_word.len();
22072                let start = snapshot.anchor_before(start);
22073                let range = start..buffer_position;
22074                let lsp_start = to_lsp(&start);
22075                let lsp_range = lsp::Range {
22076                    start: lsp_start,
22077                    end: lsp_end,
22078                };
22079                Some(Completion {
22080                    replace_range: range,
22081                    new_text: snippet.body.clone(),
22082                    source: CompletionSource::Lsp {
22083                        insert_range: None,
22084                        server_id: LanguageServerId(usize::MAX),
22085                        resolved: true,
22086                        lsp_completion: Box::new(lsp::CompletionItem {
22087                            label: snippet.prefix.first().unwrap().clone(),
22088                            kind: Some(CompletionItemKind::SNIPPET),
22089                            label_details: snippet.description.as_ref().map(|description| {
22090                                lsp::CompletionItemLabelDetails {
22091                                    detail: Some(description.clone()),
22092                                    description: None,
22093                                }
22094                            }),
22095                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22096                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22097                                lsp::InsertReplaceEdit {
22098                                    new_text: snippet.body.clone(),
22099                                    insert: lsp_range,
22100                                    replace: lsp_range,
22101                                },
22102                            )),
22103                            filter_text: Some(snippet.body.clone()),
22104                            sort_text: Some(char::MAX.to_string()),
22105                            ..lsp::CompletionItem::default()
22106                        }),
22107                        lsp_defaults: None,
22108                    },
22109                    label: CodeLabel {
22110                        text: matching_prefix.clone(),
22111                        runs: Vec::new(),
22112                        filter_range: 0..matching_prefix.len(),
22113                    },
22114                    icon_path: None,
22115                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22116                        single_line: snippet.name.clone().into(),
22117                        plain_text: snippet
22118                            .description
22119                            .clone()
22120                            .map(|description| description.into()),
22121                    }),
22122                    insert_text_mode: None,
22123                    confirm: None,
22124                })
22125            }))
22126        }
22127
22128        Ok(CompletionResponse {
22129            completions,
22130            is_incomplete,
22131        })
22132    })
22133}
22134
22135impl CompletionProvider for Entity<Project> {
22136    fn completions(
22137        &self,
22138        _excerpt_id: ExcerptId,
22139        buffer: &Entity<Buffer>,
22140        buffer_position: text::Anchor,
22141        options: CompletionContext,
22142        _window: &mut Window,
22143        cx: &mut Context<Editor>,
22144    ) -> Task<Result<Vec<CompletionResponse>>> {
22145        self.update(cx, |project, cx| {
22146            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22147            let project_completions = project.completions(buffer, buffer_position, options, cx);
22148            cx.background_spawn(async move {
22149                let mut responses = project_completions.await?;
22150                let snippets = snippets.await?;
22151                if !snippets.completions.is_empty() {
22152                    responses.push(snippets);
22153                }
22154                Ok(responses)
22155            })
22156        })
22157    }
22158
22159    fn resolve_completions(
22160        &self,
22161        buffer: Entity<Buffer>,
22162        completion_indices: Vec<usize>,
22163        completions: Rc<RefCell<Box<[Completion]>>>,
22164        cx: &mut Context<Editor>,
22165    ) -> Task<Result<bool>> {
22166        self.update(cx, |project, cx| {
22167            project.lsp_store().update(cx, |lsp_store, cx| {
22168                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22169            })
22170        })
22171    }
22172
22173    fn apply_additional_edits_for_completion(
22174        &self,
22175        buffer: Entity<Buffer>,
22176        completions: Rc<RefCell<Box<[Completion]>>>,
22177        completion_index: usize,
22178        push_to_history: bool,
22179        cx: &mut Context<Editor>,
22180    ) -> Task<Result<Option<language::Transaction>>> {
22181        self.update(cx, |project, cx| {
22182            project.lsp_store().update(cx, |lsp_store, cx| {
22183                lsp_store.apply_additional_edits_for_completion(
22184                    buffer,
22185                    completions,
22186                    completion_index,
22187                    push_to_history,
22188                    cx,
22189                )
22190            })
22191        })
22192    }
22193
22194    fn is_completion_trigger(
22195        &self,
22196        buffer: &Entity<Buffer>,
22197        position: language::Anchor,
22198        text: &str,
22199        trigger_in_words: bool,
22200        menu_is_open: bool,
22201        cx: &mut Context<Editor>,
22202    ) -> bool {
22203        let mut chars = text.chars();
22204        let char = if let Some(char) = chars.next() {
22205            char
22206        } else {
22207            return false;
22208        };
22209        if chars.next().is_some() {
22210            return false;
22211        }
22212
22213        let buffer = buffer.read(cx);
22214        let snapshot = buffer.snapshot();
22215        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22216            return false;
22217        }
22218        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22219        if trigger_in_words && classifier.is_word(char) {
22220            return true;
22221        }
22222
22223        buffer.completion_triggers().contains(text)
22224    }
22225}
22226
22227impl SemanticsProvider for Entity<Project> {
22228    fn hover(
22229        &self,
22230        buffer: &Entity<Buffer>,
22231        position: text::Anchor,
22232        cx: &mut App,
22233    ) -> Option<Task<Vec<project::Hover>>> {
22234        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22235    }
22236
22237    fn document_highlights(
22238        &self,
22239        buffer: &Entity<Buffer>,
22240        position: text::Anchor,
22241        cx: &mut App,
22242    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22243        Some(self.update(cx, |project, cx| {
22244            project.document_highlights(buffer, position, cx)
22245        }))
22246    }
22247
22248    fn definitions(
22249        &self,
22250        buffer: &Entity<Buffer>,
22251        position: text::Anchor,
22252        kind: GotoDefinitionKind,
22253        cx: &mut App,
22254    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22255        Some(self.update(cx, |project, cx| match kind {
22256            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22257            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22258            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22259            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22260        }))
22261    }
22262
22263    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22264        self.update(cx, |project, cx| {
22265            if project
22266                .active_debug_session(cx)
22267                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22268            {
22269                return true;
22270            }
22271
22272            buffer.update(cx, |buffer, cx| {
22273                project.any_language_server_supports_inlay_hints(buffer, cx)
22274            })
22275        })
22276    }
22277
22278    fn inline_values(
22279        &self,
22280        buffer_handle: Entity<Buffer>,
22281        range: Range<text::Anchor>,
22282        cx: &mut App,
22283    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22284        self.update(cx, |project, cx| {
22285            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22286
22287            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22288        })
22289    }
22290
22291    fn inlay_hints(
22292        &self,
22293        buffer_handle: Entity<Buffer>,
22294        range: Range<text::Anchor>,
22295        cx: &mut App,
22296    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22297        Some(self.update(cx, |project, cx| {
22298            project.inlay_hints(buffer_handle, range, cx)
22299        }))
22300    }
22301
22302    fn resolve_inlay_hint(
22303        &self,
22304        hint: InlayHint,
22305        buffer_handle: Entity<Buffer>,
22306        server_id: LanguageServerId,
22307        cx: &mut App,
22308    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22309        Some(self.update(cx, |project, cx| {
22310            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22311        }))
22312    }
22313
22314    fn range_for_rename(
22315        &self,
22316        buffer: &Entity<Buffer>,
22317        position: text::Anchor,
22318        cx: &mut App,
22319    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22320        Some(self.update(cx, |project, cx| {
22321            let buffer = buffer.clone();
22322            let task = project.prepare_rename(buffer.clone(), position, cx);
22323            cx.spawn(async move |_, cx| {
22324                Ok(match task.await? {
22325                    PrepareRenameResponse::Success(range) => Some(range),
22326                    PrepareRenameResponse::InvalidPosition => None,
22327                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22328                        // Fallback on using TreeSitter info to determine identifier range
22329                        buffer.read_with(cx, |buffer, _| {
22330                            let snapshot = buffer.snapshot();
22331                            let (range, kind) = snapshot.surrounding_word(position, false);
22332                            if kind != Some(CharKind::Word) {
22333                                return None;
22334                            }
22335                            Some(
22336                                snapshot.anchor_before(range.start)
22337                                    ..snapshot.anchor_after(range.end),
22338                            )
22339                        })?
22340                    }
22341                })
22342            })
22343        }))
22344    }
22345
22346    fn perform_rename(
22347        &self,
22348        buffer: &Entity<Buffer>,
22349        position: text::Anchor,
22350        new_name: String,
22351        cx: &mut App,
22352    ) -> Option<Task<Result<ProjectTransaction>>> {
22353        Some(self.update(cx, |project, cx| {
22354            project.perform_rename(buffer.clone(), position, new_name, cx)
22355        }))
22356    }
22357}
22358
22359fn inlay_hint_settings(
22360    location: Anchor,
22361    snapshot: &MultiBufferSnapshot,
22362    cx: &mut Context<Editor>,
22363) -> InlayHintSettings {
22364    let file = snapshot.file_at(location);
22365    let language = snapshot.language_at(location).map(|l| l.name());
22366    language_settings(language, file, cx).inlay_hints
22367}
22368
22369fn consume_contiguous_rows(
22370    contiguous_row_selections: &mut Vec<Selection<Point>>,
22371    selection: &Selection<Point>,
22372    display_map: &DisplaySnapshot,
22373    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22374) -> (MultiBufferRow, MultiBufferRow) {
22375    contiguous_row_selections.push(selection.clone());
22376    let start_row = starting_row(selection, display_map);
22377    let mut end_row = ending_row(selection, display_map);
22378
22379    while let Some(next_selection) = selections.peek() {
22380        if next_selection.start.row <= end_row.0 {
22381            end_row = ending_row(next_selection, display_map);
22382            contiguous_row_selections.push(selections.next().unwrap().clone());
22383        } else {
22384            break;
22385        }
22386    }
22387    (start_row, end_row)
22388}
22389
22390fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22391    if selection.start.column > 0 {
22392        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22393    } else {
22394        MultiBufferRow(selection.start.row)
22395    }
22396}
22397
22398fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22399    if next_selection.end.column > 0 || next_selection.is_empty() {
22400        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22401    } else {
22402        MultiBufferRow(next_selection.end.row)
22403    }
22404}
22405
22406impl EditorSnapshot {
22407    pub fn remote_selections_in_range<'a>(
22408        &'a self,
22409        range: &'a Range<Anchor>,
22410        collaboration_hub: &dyn CollaborationHub,
22411        cx: &'a App,
22412    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22413        let participant_names = collaboration_hub.user_names(cx);
22414        let participant_indices = collaboration_hub.user_participant_indices(cx);
22415        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22416        let collaborators_by_replica_id = collaborators_by_peer_id
22417            .values()
22418            .map(|collaborator| (collaborator.replica_id, collaborator))
22419            .collect::<HashMap<_, _>>();
22420        self.buffer_snapshot
22421            .selections_in_range(range, false)
22422            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22423                if replica_id == AGENT_REPLICA_ID {
22424                    Some(RemoteSelection {
22425                        replica_id,
22426                        selection,
22427                        cursor_shape,
22428                        line_mode,
22429                        collaborator_id: CollaboratorId::Agent,
22430                        user_name: Some("Agent".into()),
22431                        color: cx.theme().players().agent(),
22432                    })
22433                } else {
22434                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22435                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22436                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22437                    Some(RemoteSelection {
22438                        replica_id,
22439                        selection,
22440                        cursor_shape,
22441                        line_mode,
22442                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22443                        user_name,
22444                        color: if let Some(index) = participant_index {
22445                            cx.theme().players().color_for_participant(index.0)
22446                        } else {
22447                            cx.theme().players().absent()
22448                        },
22449                    })
22450                }
22451            })
22452    }
22453
22454    pub fn hunks_for_ranges(
22455        &self,
22456        ranges: impl IntoIterator<Item = Range<Point>>,
22457    ) -> Vec<MultiBufferDiffHunk> {
22458        let mut hunks = Vec::new();
22459        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22460            HashMap::default();
22461        for query_range in ranges {
22462            let query_rows =
22463                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22464            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22465                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22466            ) {
22467                // Include deleted hunks that are adjacent to the query range, because
22468                // otherwise they would be missed.
22469                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22470                if hunk.status().is_deleted() {
22471                    intersects_range |= hunk.row_range.start == query_rows.end;
22472                    intersects_range |= hunk.row_range.end == query_rows.start;
22473                }
22474                if intersects_range {
22475                    if !processed_buffer_rows
22476                        .entry(hunk.buffer_id)
22477                        .or_default()
22478                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22479                    {
22480                        continue;
22481                    }
22482                    hunks.push(hunk);
22483                }
22484            }
22485        }
22486
22487        hunks
22488    }
22489
22490    fn display_diff_hunks_for_rows<'a>(
22491        &'a self,
22492        display_rows: Range<DisplayRow>,
22493        folded_buffers: &'a HashSet<BufferId>,
22494    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22495        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22496        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22497
22498        self.buffer_snapshot
22499            .diff_hunks_in_range(buffer_start..buffer_end)
22500            .filter_map(|hunk| {
22501                if folded_buffers.contains(&hunk.buffer_id) {
22502                    return None;
22503                }
22504
22505                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22506                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22507
22508                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22509                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22510
22511                let display_hunk = if hunk_display_start.column() != 0 {
22512                    DisplayDiffHunk::Folded {
22513                        display_row: hunk_display_start.row(),
22514                    }
22515                } else {
22516                    let mut end_row = hunk_display_end.row();
22517                    if hunk_display_end.column() > 0 {
22518                        end_row.0 += 1;
22519                    }
22520                    let is_created_file = hunk.is_created_file();
22521                    DisplayDiffHunk::Unfolded {
22522                        status: hunk.status(),
22523                        diff_base_byte_range: hunk.diff_base_byte_range,
22524                        display_row_range: hunk_display_start.row()..end_row,
22525                        multi_buffer_range: Anchor::range_in_buffer(
22526                            hunk.excerpt_id,
22527                            hunk.buffer_id,
22528                            hunk.buffer_range,
22529                        ),
22530                        is_created_file,
22531                    }
22532                };
22533
22534                Some(display_hunk)
22535            })
22536    }
22537
22538    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22539        self.display_snapshot.buffer_snapshot.language_at(position)
22540    }
22541
22542    pub fn is_focused(&self) -> bool {
22543        self.is_focused
22544    }
22545
22546    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22547        self.placeholder_text.as_ref()
22548    }
22549
22550    pub fn scroll_position(&self) -> gpui::Point<f32> {
22551        self.scroll_anchor.scroll_position(&self.display_snapshot)
22552    }
22553
22554    fn gutter_dimensions(
22555        &self,
22556        font_id: FontId,
22557        font_size: Pixels,
22558        max_line_number_width: Pixels,
22559        cx: &App,
22560    ) -> Option<GutterDimensions> {
22561        if !self.show_gutter {
22562            return None;
22563        }
22564
22565        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22566        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22567
22568        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22569            matches!(
22570                ProjectSettings::get_global(cx).git.git_gutter,
22571                Some(GitGutterSetting::TrackedFiles)
22572            )
22573        });
22574        let gutter_settings = EditorSettings::get_global(cx).gutter;
22575        let show_line_numbers = self
22576            .show_line_numbers
22577            .unwrap_or(gutter_settings.line_numbers);
22578        let line_gutter_width = if show_line_numbers {
22579            // Avoid flicker-like gutter resizes when the line number gains another digit by
22580            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22581            let min_width_for_number_on_gutter =
22582                ch_advance * gutter_settings.min_line_number_digits as f32;
22583            max_line_number_width.max(min_width_for_number_on_gutter)
22584        } else {
22585            0.0.into()
22586        };
22587
22588        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22589        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22590
22591        let git_blame_entries_width =
22592            self.git_blame_gutter_max_author_length
22593                .map(|max_author_length| {
22594                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22595                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22596
22597                    /// The number of characters to dedicate to gaps and margins.
22598                    const SPACING_WIDTH: usize = 4;
22599
22600                    let max_char_count = max_author_length.min(renderer.max_author_length())
22601                        + ::git::SHORT_SHA_LENGTH
22602                        + MAX_RELATIVE_TIMESTAMP.len()
22603                        + SPACING_WIDTH;
22604
22605                    ch_advance * max_char_count
22606                });
22607
22608        let is_singleton = self.buffer_snapshot.is_singleton();
22609
22610        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22611        left_padding += if !is_singleton {
22612            ch_width * 4.0
22613        } else if show_runnables || show_breakpoints {
22614            ch_width * 3.0
22615        } else if show_git_gutter && show_line_numbers {
22616            ch_width * 2.0
22617        } else if show_git_gutter || show_line_numbers {
22618            ch_width
22619        } else {
22620            px(0.)
22621        };
22622
22623        let shows_folds = is_singleton && gutter_settings.folds;
22624
22625        let right_padding = if shows_folds && show_line_numbers {
22626            ch_width * 4.0
22627        } else if shows_folds || (!is_singleton && show_line_numbers) {
22628            ch_width * 3.0
22629        } else if show_line_numbers {
22630            ch_width
22631        } else {
22632            px(0.)
22633        };
22634
22635        Some(GutterDimensions {
22636            left_padding,
22637            right_padding,
22638            width: line_gutter_width + left_padding + right_padding,
22639            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22640            git_blame_entries_width,
22641        })
22642    }
22643
22644    pub fn render_crease_toggle(
22645        &self,
22646        buffer_row: MultiBufferRow,
22647        row_contains_cursor: bool,
22648        editor: Entity<Editor>,
22649        window: &mut Window,
22650        cx: &mut App,
22651    ) -> Option<AnyElement> {
22652        let folded = self.is_line_folded(buffer_row);
22653        let mut is_foldable = false;
22654
22655        if let Some(crease) = self
22656            .crease_snapshot
22657            .query_row(buffer_row, &self.buffer_snapshot)
22658        {
22659            is_foldable = true;
22660            match crease {
22661                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22662                    if let Some(render_toggle) = render_toggle {
22663                        let toggle_callback =
22664                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22665                                if folded {
22666                                    editor.update(cx, |editor, cx| {
22667                                        editor.fold_at(buffer_row, window, cx)
22668                                    });
22669                                } else {
22670                                    editor.update(cx, |editor, cx| {
22671                                        editor.unfold_at(buffer_row, window, cx)
22672                                    });
22673                                }
22674                            });
22675                        return Some((render_toggle)(
22676                            buffer_row,
22677                            folded,
22678                            toggle_callback,
22679                            window,
22680                            cx,
22681                        ));
22682                    }
22683                }
22684            }
22685        }
22686
22687        is_foldable |= self.starts_indent(buffer_row);
22688
22689        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22690            Some(
22691                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22692                    .toggle_state(folded)
22693                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22694                        if folded {
22695                            this.unfold_at(buffer_row, window, cx);
22696                        } else {
22697                            this.fold_at(buffer_row, window, cx);
22698                        }
22699                    }))
22700                    .into_any_element(),
22701            )
22702        } else {
22703            None
22704        }
22705    }
22706
22707    pub fn render_crease_trailer(
22708        &self,
22709        buffer_row: MultiBufferRow,
22710        window: &mut Window,
22711        cx: &mut App,
22712    ) -> Option<AnyElement> {
22713        let folded = self.is_line_folded(buffer_row);
22714        if let Crease::Inline { render_trailer, .. } = self
22715            .crease_snapshot
22716            .query_row(buffer_row, &self.buffer_snapshot)?
22717        {
22718            let render_trailer = render_trailer.as_ref()?;
22719            Some(render_trailer(buffer_row, folded, window, cx))
22720        } else {
22721            None
22722        }
22723    }
22724}
22725
22726impl Deref for EditorSnapshot {
22727    type Target = DisplaySnapshot;
22728
22729    fn deref(&self) -> &Self::Target {
22730        &self.display_snapshot
22731    }
22732}
22733
22734#[derive(Clone, Debug, PartialEq, Eq)]
22735pub enum EditorEvent {
22736    InputIgnored {
22737        text: Arc<str>,
22738    },
22739    InputHandled {
22740        utf16_range_to_replace: Option<Range<isize>>,
22741        text: Arc<str>,
22742    },
22743    ExcerptsAdded {
22744        buffer: Entity<Buffer>,
22745        predecessor: ExcerptId,
22746        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22747    },
22748    ExcerptsRemoved {
22749        ids: Vec<ExcerptId>,
22750        removed_buffer_ids: Vec<BufferId>,
22751    },
22752    BufferFoldToggled {
22753        ids: Vec<ExcerptId>,
22754        folded: bool,
22755    },
22756    ExcerptsEdited {
22757        ids: Vec<ExcerptId>,
22758    },
22759    ExcerptsExpanded {
22760        ids: Vec<ExcerptId>,
22761    },
22762    BufferEdited,
22763    Edited {
22764        transaction_id: clock::Lamport,
22765    },
22766    Reparsed(BufferId),
22767    Focused,
22768    FocusedIn,
22769    Blurred,
22770    DirtyChanged,
22771    Saved,
22772    TitleChanged,
22773    DiffBaseChanged,
22774    SelectionsChanged {
22775        local: bool,
22776    },
22777    ScrollPositionChanged {
22778        local: bool,
22779        autoscroll: bool,
22780    },
22781    Closed,
22782    TransactionUndone {
22783        transaction_id: clock::Lamport,
22784    },
22785    TransactionBegun {
22786        transaction_id: clock::Lamport,
22787    },
22788    Reloaded,
22789    CursorShapeChanged,
22790    BreadcrumbsChanged,
22791    PushedToNavHistory {
22792        anchor: Anchor,
22793        is_deactivate: bool,
22794    },
22795}
22796
22797impl EventEmitter<EditorEvent> for Editor {}
22798
22799impl Focusable for Editor {
22800    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22801        self.focus_handle.clone()
22802    }
22803}
22804
22805impl Render for Editor {
22806    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22807        let settings = ThemeSettings::get_global(cx);
22808
22809        let mut text_style = match self.mode {
22810            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22811                color: cx.theme().colors().editor_foreground,
22812                font_family: settings.ui_font.family.clone(),
22813                font_features: settings.ui_font.features.clone(),
22814                font_fallbacks: settings.ui_font.fallbacks.clone(),
22815                font_size: rems(0.875).into(),
22816                font_weight: settings.ui_font.weight,
22817                line_height: relative(settings.buffer_line_height.value()),
22818                ..Default::default()
22819            },
22820            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22821                color: cx.theme().colors().editor_foreground,
22822                font_family: settings.buffer_font.family.clone(),
22823                font_features: settings.buffer_font.features.clone(),
22824                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22825                font_size: settings.buffer_font_size(cx).into(),
22826                font_weight: settings.buffer_font.weight,
22827                line_height: relative(settings.buffer_line_height.value()),
22828                ..Default::default()
22829            },
22830        };
22831        if let Some(text_style_refinement) = &self.text_style_refinement {
22832            text_style.refine(text_style_refinement)
22833        }
22834
22835        let background = match self.mode {
22836            EditorMode::SingleLine => cx.theme().system().transparent,
22837            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22838            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22839            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22840        };
22841
22842        EditorElement::new(
22843            &cx.entity(),
22844            EditorStyle {
22845                background,
22846                border: cx.theme().colors().border,
22847                local_player: cx.theme().players().local(),
22848                text: text_style,
22849                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22850                syntax: cx.theme().syntax().clone(),
22851                status: cx.theme().status().clone(),
22852                inlay_hints_style: make_inlay_hints_style(cx),
22853                edit_prediction_styles: make_suggestion_styles(cx),
22854                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22855                show_underlines: self.diagnostics_enabled(),
22856            },
22857        )
22858    }
22859}
22860
22861impl EntityInputHandler for Editor {
22862    fn text_for_range(
22863        &mut self,
22864        range_utf16: Range<usize>,
22865        adjusted_range: &mut Option<Range<usize>>,
22866        _: &mut Window,
22867        cx: &mut Context<Self>,
22868    ) -> Option<String> {
22869        let snapshot = self.buffer.read(cx).read(cx);
22870        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22871        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22872        if (start.0..end.0) != range_utf16 {
22873            adjusted_range.replace(start.0..end.0);
22874        }
22875        Some(snapshot.text_for_range(start..end).collect())
22876    }
22877
22878    fn selected_text_range(
22879        &mut self,
22880        ignore_disabled_input: bool,
22881        _: &mut Window,
22882        cx: &mut Context<Self>,
22883    ) -> Option<UTF16Selection> {
22884        // Prevent the IME menu from appearing when holding down an alphabetic key
22885        // while input is disabled.
22886        if !ignore_disabled_input && !self.input_enabled {
22887            return None;
22888        }
22889
22890        let selection = self.selections.newest::<OffsetUtf16>(cx);
22891        let range = selection.range();
22892
22893        Some(UTF16Selection {
22894            range: range.start.0..range.end.0,
22895            reversed: selection.reversed,
22896        })
22897    }
22898
22899    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22900        let snapshot = self.buffer.read(cx).read(cx);
22901        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22902        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22903    }
22904
22905    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22906        self.clear_highlights::<InputComposition>(cx);
22907        self.ime_transaction.take();
22908    }
22909
22910    fn replace_text_in_range(
22911        &mut self,
22912        range_utf16: Option<Range<usize>>,
22913        text: &str,
22914        window: &mut Window,
22915        cx: &mut Context<Self>,
22916    ) {
22917        if !self.input_enabled {
22918            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22919            return;
22920        }
22921
22922        self.transact(window, cx, |this, window, cx| {
22923            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22924                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22925                Some(this.selection_replacement_ranges(range_utf16, cx))
22926            } else {
22927                this.marked_text_ranges(cx)
22928            };
22929
22930            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22931                let newest_selection_id = this.selections.newest_anchor().id;
22932                this.selections
22933                    .all::<OffsetUtf16>(cx)
22934                    .iter()
22935                    .zip(ranges_to_replace.iter())
22936                    .find_map(|(selection, range)| {
22937                        if selection.id == newest_selection_id {
22938                            Some(
22939                                (range.start.0 as isize - selection.head().0 as isize)
22940                                    ..(range.end.0 as isize - selection.head().0 as isize),
22941                            )
22942                        } else {
22943                            None
22944                        }
22945                    })
22946            });
22947
22948            cx.emit(EditorEvent::InputHandled {
22949                utf16_range_to_replace: range_to_replace,
22950                text: text.into(),
22951            });
22952
22953            if let Some(new_selected_ranges) = new_selected_ranges {
22954                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22955                    selections.select_ranges(new_selected_ranges)
22956                });
22957                this.backspace(&Default::default(), window, cx);
22958            }
22959
22960            this.handle_input(text, window, cx);
22961        });
22962
22963        if let Some(transaction) = self.ime_transaction {
22964            self.buffer.update(cx, |buffer, cx| {
22965                buffer.group_until_transaction(transaction, cx);
22966            });
22967        }
22968
22969        self.unmark_text(window, cx);
22970    }
22971
22972    fn replace_and_mark_text_in_range(
22973        &mut self,
22974        range_utf16: Option<Range<usize>>,
22975        text: &str,
22976        new_selected_range_utf16: Option<Range<usize>>,
22977        window: &mut Window,
22978        cx: &mut Context<Self>,
22979    ) {
22980        if !self.input_enabled {
22981            return;
22982        }
22983
22984        let transaction = self.transact(window, cx, |this, window, cx| {
22985            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22986                let snapshot = this.buffer.read(cx).read(cx);
22987                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22988                    for marked_range in &mut marked_ranges {
22989                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22990                        marked_range.start.0 += relative_range_utf16.start;
22991                        marked_range.start =
22992                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22993                        marked_range.end =
22994                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22995                    }
22996                }
22997                Some(marked_ranges)
22998            } else if let Some(range_utf16) = range_utf16 {
22999                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23000                Some(this.selection_replacement_ranges(range_utf16, cx))
23001            } else {
23002                None
23003            };
23004
23005            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23006                let newest_selection_id = this.selections.newest_anchor().id;
23007                this.selections
23008                    .all::<OffsetUtf16>(cx)
23009                    .iter()
23010                    .zip(ranges_to_replace.iter())
23011                    .find_map(|(selection, range)| {
23012                        if selection.id == newest_selection_id {
23013                            Some(
23014                                (range.start.0 as isize - selection.head().0 as isize)
23015                                    ..(range.end.0 as isize - selection.head().0 as isize),
23016                            )
23017                        } else {
23018                            None
23019                        }
23020                    })
23021            });
23022
23023            cx.emit(EditorEvent::InputHandled {
23024                utf16_range_to_replace: range_to_replace,
23025                text: text.into(),
23026            });
23027
23028            if let Some(ranges) = ranges_to_replace {
23029                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23030                    s.select_ranges(ranges)
23031                });
23032            }
23033
23034            let marked_ranges = {
23035                let snapshot = this.buffer.read(cx).read(cx);
23036                this.selections
23037                    .disjoint_anchors()
23038                    .iter()
23039                    .map(|selection| {
23040                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23041                    })
23042                    .collect::<Vec<_>>()
23043            };
23044
23045            if text.is_empty() {
23046                this.unmark_text(window, cx);
23047            } else {
23048                this.highlight_text::<InputComposition>(
23049                    marked_ranges.clone(),
23050                    HighlightStyle {
23051                        underline: Some(UnderlineStyle {
23052                            thickness: px(1.),
23053                            color: None,
23054                            wavy: false,
23055                        }),
23056                        ..Default::default()
23057                    },
23058                    cx,
23059                );
23060            }
23061
23062            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23063            let use_autoclose = this.use_autoclose;
23064            let use_auto_surround = this.use_auto_surround;
23065            this.set_use_autoclose(false);
23066            this.set_use_auto_surround(false);
23067            this.handle_input(text, window, cx);
23068            this.set_use_autoclose(use_autoclose);
23069            this.set_use_auto_surround(use_auto_surround);
23070
23071            if let Some(new_selected_range) = new_selected_range_utf16 {
23072                let snapshot = this.buffer.read(cx).read(cx);
23073                let new_selected_ranges = marked_ranges
23074                    .into_iter()
23075                    .map(|marked_range| {
23076                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23077                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23078                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23079                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23080                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23081                    })
23082                    .collect::<Vec<_>>();
23083
23084                drop(snapshot);
23085                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23086                    selections.select_ranges(new_selected_ranges)
23087                });
23088            }
23089        });
23090
23091        self.ime_transaction = self.ime_transaction.or(transaction);
23092        if let Some(transaction) = self.ime_transaction {
23093            self.buffer.update(cx, |buffer, cx| {
23094                buffer.group_until_transaction(transaction, cx);
23095            });
23096        }
23097
23098        if self.text_highlights::<InputComposition>(cx).is_none() {
23099            self.ime_transaction.take();
23100        }
23101    }
23102
23103    fn bounds_for_range(
23104        &mut self,
23105        range_utf16: Range<usize>,
23106        element_bounds: gpui::Bounds<Pixels>,
23107        window: &mut Window,
23108        cx: &mut Context<Self>,
23109    ) -> Option<gpui::Bounds<Pixels>> {
23110        let text_layout_details = self.text_layout_details(window);
23111        let CharacterDimensions {
23112            em_width,
23113            em_advance,
23114            line_height,
23115        } = self.character_dimensions(window);
23116
23117        let snapshot = self.snapshot(window, cx);
23118        let scroll_position = snapshot.scroll_position();
23119        let scroll_left = scroll_position.x * em_advance;
23120
23121        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23122        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23123            + self.gutter_dimensions.full_width();
23124        let y = line_height * (start.row().as_f32() - scroll_position.y);
23125
23126        Some(Bounds {
23127            origin: element_bounds.origin + point(x, y),
23128            size: size(em_width, line_height),
23129        })
23130    }
23131
23132    fn character_index_for_point(
23133        &mut self,
23134        point: gpui::Point<Pixels>,
23135        _window: &mut Window,
23136        _cx: &mut Context<Self>,
23137    ) -> Option<usize> {
23138        let position_map = self.last_position_map.as_ref()?;
23139        if !position_map.text_hitbox.contains(&point) {
23140            return None;
23141        }
23142        let display_point = position_map.point_for_position(point).previous_valid;
23143        let anchor = position_map
23144            .snapshot
23145            .display_point_to_anchor(display_point, Bias::Left);
23146        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23147        Some(utf16_offset.0)
23148    }
23149}
23150
23151trait SelectionExt {
23152    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23153    fn spanned_rows(
23154        &self,
23155        include_end_if_at_line_start: bool,
23156        map: &DisplaySnapshot,
23157    ) -> Range<MultiBufferRow>;
23158}
23159
23160impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23161    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23162        let start = self
23163            .start
23164            .to_point(&map.buffer_snapshot)
23165            .to_display_point(map);
23166        let end = self
23167            .end
23168            .to_point(&map.buffer_snapshot)
23169            .to_display_point(map);
23170        if self.reversed {
23171            end..start
23172        } else {
23173            start..end
23174        }
23175    }
23176
23177    fn spanned_rows(
23178        &self,
23179        include_end_if_at_line_start: bool,
23180        map: &DisplaySnapshot,
23181    ) -> Range<MultiBufferRow> {
23182        let start = self.start.to_point(&map.buffer_snapshot);
23183        let mut end = self.end.to_point(&map.buffer_snapshot);
23184        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23185            end.row -= 1;
23186        }
23187
23188        let buffer_start = map.prev_line_boundary(start).0;
23189        let buffer_end = map.next_line_boundary(end).0;
23190        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23191    }
23192}
23193
23194impl<T: InvalidationRegion> InvalidationStack<T> {
23195    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23196    where
23197        S: Clone + ToOffset,
23198    {
23199        while let Some(region) = self.last() {
23200            let all_selections_inside_invalidation_ranges =
23201                if selections.len() == region.ranges().len() {
23202                    selections
23203                        .iter()
23204                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23205                        .all(|(selection, invalidation_range)| {
23206                            let head = selection.head().to_offset(buffer);
23207                            invalidation_range.start <= head && invalidation_range.end >= head
23208                        })
23209                } else {
23210                    false
23211                };
23212
23213            if all_selections_inside_invalidation_ranges {
23214                break;
23215            } else {
23216                self.pop();
23217            }
23218        }
23219    }
23220}
23221
23222impl<T> Default for InvalidationStack<T> {
23223    fn default() -> Self {
23224        Self(Default::default())
23225    }
23226}
23227
23228impl<T> Deref for InvalidationStack<T> {
23229    type Target = Vec<T>;
23230
23231    fn deref(&self) -> &Self::Target {
23232        &self.0
23233    }
23234}
23235
23236impl<T> DerefMut for InvalidationStack<T> {
23237    fn deref_mut(&mut self) -> &mut Self::Target {
23238        &mut self.0
23239    }
23240}
23241
23242impl InvalidationRegion for SnippetState {
23243    fn ranges(&self) -> &[Range<Anchor>] {
23244        &self.ranges[self.active_index]
23245    }
23246}
23247
23248fn edit_prediction_edit_text(
23249    current_snapshot: &BufferSnapshot,
23250    edits: &[(Range<Anchor>, String)],
23251    edit_preview: &EditPreview,
23252    include_deletions: bool,
23253    cx: &App,
23254) -> HighlightedText {
23255    let edits = edits
23256        .iter()
23257        .map(|(anchor, text)| {
23258            (
23259                anchor.start.text_anchor..anchor.end.text_anchor,
23260                text.clone(),
23261            )
23262        })
23263        .collect::<Vec<_>>();
23264
23265    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23266}
23267
23268fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23269    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23270    // Just show the raw edit text with basic styling
23271    let mut text = String::new();
23272    let mut highlights = Vec::new();
23273
23274    let insertion_highlight_style = HighlightStyle {
23275        color: Some(cx.theme().colors().text),
23276        ..Default::default()
23277    };
23278
23279    for (_, edit_text) in edits {
23280        let start_offset = text.len();
23281        text.push_str(edit_text);
23282        let end_offset = text.len();
23283
23284        if start_offset < end_offset {
23285            highlights.push((start_offset..end_offset, insertion_highlight_style));
23286        }
23287    }
23288
23289    HighlightedText {
23290        text: text.into(),
23291        highlights,
23292    }
23293}
23294
23295pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23296    match severity {
23297        lsp::DiagnosticSeverity::ERROR => colors.error,
23298        lsp::DiagnosticSeverity::WARNING => colors.warning,
23299        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23300        lsp::DiagnosticSeverity::HINT => colors.info,
23301        _ => colors.ignored,
23302    }
23303}
23304
23305pub fn styled_runs_for_code_label<'a>(
23306    label: &'a CodeLabel,
23307    syntax_theme: &'a theme::SyntaxTheme,
23308) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23309    let fade_out = HighlightStyle {
23310        fade_out: Some(0.35),
23311        ..Default::default()
23312    };
23313
23314    let mut prev_end = label.filter_range.end;
23315    label
23316        .runs
23317        .iter()
23318        .enumerate()
23319        .flat_map(move |(ix, (range, highlight_id))| {
23320            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23321                style
23322            } else {
23323                return Default::default();
23324            };
23325            let mut muted_style = style;
23326            muted_style.highlight(fade_out);
23327
23328            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23329            if range.start >= label.filter_range.end {
23330                if range.start > prev_end {
23331                    runs.push((prev_end..range.start, fade_out));
23332                }
23333                runs.push((range.clone(), muted_style));
23334            } else if range.end <= label.filter_range.end {
23335                runs.push((range.clone(), style));
23336            } else {
23337                runs.push((range.start..label.filter_range.end, style));
23338                runs.push((label.filter_range.end..range.end, muted_style));
23339            }
23340            prev_end = cmp::max(prev_end, range.end);
23341
23342            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23343                runs.push((prev_end..label.text.len(), fade_out));
23344            }
23345
23346            runs
23347        })
23348}
23349
23350pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23351    let mut prev_index = 0;
23352    let mut prev_codepoint: Option<char> = None;
23353    text.char_indices()
23354        .chain([(text.len(), '\0')])
23355        .filter_map(move |(index, codepoint)| {
23356            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23357            let is_boundary = index == text.len()
23358                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23359                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23360            if is_boundary {
23361                let chunk = &text[prev_index..index];
23362                prev_index = index;
23363                Some(chunk)
23364            } else {
23365                None
23366            }
23367        })
23368}
23369
23370pub trait RangeToAnchorExt: Sized {
23371    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23372
23373    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23374        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23375        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23376    }
23377}
23378
23379impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23380    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23381        let start_offset = self.start.to_offset(snapshot);
23382        let end_offset = self.end.to_offset(snapshot);
23383        if start_offset == end_offset {
23384            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23385        } else {
23386            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23387        }
23388    }
23389}
23390
23391pub trait RowExt {
23392    fn as_f32(&self) -> f32;
23393
23394    fn next_row(&self) -> Self;
23395
23396    fn previous_row(&self) -> Self;
23397
23398    fn minus(&self, other: Self) -> u32;
23399}
23400
23401impl RowExt for DisplayRow {
23402    fn as_f32(&self) -> f32 {
23403        self.0 as f32
23404    }
23405
23406    fn next_row(&self) -> Self {
23407        Self(self.0 + 1)
23408    }
23409
23410    fn previous_row(&self) -> Self {
23411        Self(self.0.saturating_sub(1))
23412    }
23413
23414    fn minus(&self, other: Self) -> u32 {
23415        self.0 - other.0
23416    }
23417}
23418
23419impl RowExt for MultiBufferRow {
23420    fn as_f32(&self) -> f32 {
23421        self.0 as f32
23422    }
23423
23424    fn next_row(&self) -> Self {
23425        Self(self.0 + 1)
23426    }
23427
23428    fn previous_row(&self) -> Self {
23429        Self(self.0.saturating_sub(1))
23430    }
23431
23432    fn minus(&self, other: Self) -> u32 {
23433        self.0 - other.0
23434    }
23435}
23436
23437trait RowRangeExt {
23438    type Row;
23439
23440    fn len(&self) -> usize;
23441
23442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23443}
23444
23445impl RowRangeExt for Range<MultiBufferRow> {
23446    type Row = MultiBufferRow;
23447
23448    fn len(&self) -> usize {
23449        (self.end.0 - self.start.0) as usize
23450    }
23451
23452    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23453        (self.start.0..self.end.0).map(MultiBufferRow)
23454    }
23455}
23456
23457impl RowRangeExt for Range<DisplayRow> {
23458    type Row = DisplayRow;
23459
23460    fn len(&self) -> usize {
23461        (self.end.0 - self.start.0) as usize
23462    }
23463
23464    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23465        (self.start.0..self.end.0).map(DisplayRow)
23466    }
23467}
23468
23469/// If select range has more than one line, we
23470/// just point the cursor to range.start.
23471fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23472    if range.start.row == range.end.row {
23473        range
23474    } else {
23475        range.start..range.start
23476    }
23477}
23478pub struct KillRing(ClipboardItem);
23479impl Global for KillRing {}
23480
23481const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23482
23483enum BreakpointPromptEditAction {
23484    Log,
23485    Condition,
23486    HitCondition,
23487}
23488
23489struct BreakpointPromptEditor {
23490    pub(crate) prompt: Entity<Editor>,
23491    editor: WeakEntity<Editor>,
23492    breakpoint_anchor: Anchor,
23493    breakpoint: Breakpoint,
23494    edit_action: BreakpointPromptEditAction,
23495    block_ids: HashSet<CustomBlockId>,
23496    editor_margins: Arc<Mutex<EditorMargins>>,
23497    _subscriptions: Vec<Subscription>,
23498}
23499
23500impl BreakpointPromptEditor {
23501    const MAX_LINES: u8 = 4;
23502
23503    fn new(
23504        editor: WeakEntity<Editor>,
23505        breakpoint_anchor: Anchor,
23506        breakpoint: Breakpoint,
23507        edit_action: BreakpointPromptEditAction,
23508        window: &mut Window,
23509        cx: &mut Context<Self>,
23510    ) -> Self {
23511        let base_text = match edit_action {
23512            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23513            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23514            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23515        }
23516        .map(|msg| msg.to_string())
23517        .unwrap_or_default();
23518
23519        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23520        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23521
23522        let prompt = cx.new(|cx| {
23523            let mut prompt = Editor::new(
23524                EditorMode::AutoHeight {
23525                    min_lines: 1,
23526                    max_lines: Some(Self::MAX_LINES as usize),
23527                },
23528                buffer,
23529                None,
23530                window,
23531                cx,
23532            );
23533            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23534            prompt.set_show_cursor_when_unfocused(false, cx);
23535            prompt.set_placeholder_text(
23536                match edit_action {
23537                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23538                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23539                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23540                },
23541                cx,
23542            );
23543
23544            prompt
23545        });
23546
23547        Self {
23548            prompt,
23549            editor,
23550            breakpoint_anchor,
23551            breakpoint,
23552            edit_action,
23553            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23554            block_ids: Default::default(),
23555            _subscriptions: vec![],
23556        }
23557    }
23558
23559    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23560        self.block_ids.extend(block_ids)
23561    }
23562
23563    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23564        if let Some(editor) = self.editor.upgrade() {
23565            let message = self
23566                .prompt
23567                .read(cx)
23568                .buffer
23569                .read(cx)
23570                .as_singleton()
23571                .expect("A multi buffer in breakpoint prompt isn't possible")
23572                .read(cx)
23573                .as_rope()
23574                .to_string();
23575
23576            editor.update(cx, |editor, cx| {
23577                editor.edit_breakpoint_at_anchor(
23578                    self.breakpoint_anchor,
23579                    self.breakpoint.clone(),
23580                    match self.edit_action {
23581                        BreakpointPromptEditAction::Log => {
23582                            BreakpointEditAction::EditLogMessage(message.into())
23583                        }
23584                        BreakpointPromptEditAction::Condition => {
23585                            BreakpointEditAction::EditCondition(message.into())
23586                        }
23587                        BreakpointPromptEditAction::HitCondition => {
23588                            BreakpointEditAction::EditHitCondition(message.into())
23589                        }
23590                    },
23591                    cx,
23592                );
23593
23594                editor.remove_blocks(self.block_ids.clone(), None, cx);
23595                cx.focus_self(window);
23596            });
23597        }
23598    }
23599
23600    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23601        self.editor
23602            .update(cx, |editor, cx| {
23603                editor.remove_blocks(self.block_ids.clone(), None, cx);
23604                window.focus(&editor.focus_handle);
23605            })
23606            .log_err();
23607    }
23608
23609    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23610        let settings = ThemeSettings::get_global(cx);
23611        let text_style = TextStyle {
23612            color: if self.prompt.read(cx).read_only(cx) {
23613                cx.theme().colors().text_disabled
23614            } else {
23615                cx.theme().colors().text
23616            },
23617            font_family: settings.buffer_font.family.clone(),
23618            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23619            font_size: settings.buffer_font_size(cx).into(),
23620            font_weight: settings.buffer_font.weight,
23621            line_height: relative(settings.buffer_line_height.value()),
23622            ..Default::default()
23623        };
23624        EditorElement::new(
23625            &self.prompt,
23626            EditorStyle {
23627                background: cx.theme().colors().editor_background,
23628                local_player: cx.theme().players().local(),
23629                text: text_style,
23630                ..Default::default()
23631            },
23632        )
23633    }
23634}
23635
23636impl Render for BreakpointPromptEditor {
23637    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23638        let editor_margins = *self.editor_margins.lock();
23639        let gutter_dimensions = editor_margins.gutter;
23640        h_flex()
23641            .key_context("Editor")
23642            .bg(cx.theme().colors().editor_background)
23643            .border_y_1()
23644            .border_color(cx.theme().status().info_border)
23645            .size_full()
23646            .py(window.line_height() / 2.5)
23647            .on_action(cx.listener(Self::confirm))
23648            .on_action(cx.listener(Self::cancel))
23649            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23650            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23651    }
23652}
23653
23654impl Focusable for BreakpointPromptEditor {
23655    fn focus_handle(&self, cx: &App) -> FocusHandle {
23656        self.prompt.focus_handle(cx)
23657    }
23658}
23659
23660fn all_edits_insertions_or_deletions(
23661    edits: &Vec<(Range<Anchor>, String)>,
23662    snapshot: &MultiBufferSnapshot,
23663) -> bool {
23664    let mut all_insertions = true;
23665    let mut all_deletions = true;
23666
23667    for (range, new_text) in edits.iter() {
23668        let range_is_empty = range.to_offset(snapshot).is_empty();
23669        let text_is_empty = new_text.is_empty();
23670
23671        if range_is_empty != text_is_empty {
23672            if range_is_empty {
23673                all_deletions = false;
23674            } else {
23675                all_insertions = false;
23676            }
23677        } else {
23678            return false;
23679        }
23680
23681        if !all_insertions && !all_deletions {
23682            return false;
23683        }
23684    }
23685    all_insertions || all_deletions
23686}
23687
23688struct MissingEditPredictionKeybindingTooltip;
23689
23690impl Render for MissingEditPredictionKeybindingTooltip {
23691    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23692        ui::tooltip_container(window, cx, |container, _, cx| {
23693            container
23694                .flex_shrink_0()
23695                .max_w_80()
23696                .min_h(rems_from_px(124.))
23697                .justify_between()
23698                .child(
23699                    v_flex()
23700                        .flex_1()
23701                        .text_ui_sm(cx)
23702                        .child(Label::new("Conflict with Accept Keybinding"))
23703                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23704                )
23705                .child(
23706                    h_flex()
23707                        .pb_1()
23708                        .gap_1()
23709                        .items_end()
23710                        .w_full()
23711                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23712                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23713                        }))
23714                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23715                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23716                        })),
23717                )
23718        })
23719    }
23720}
23721
23722#[derive(Debug, Clone, Copy, PartialEq)]
23723pub struct LineHighlight {
23724    pub background: Background,
23725    pub border: Option<gpui::Hsla>,
23726    pub include_gutter: bool,
23727    pub type_id: Option<TypeId>,
23728}
23729
23730struct LineManipulationResult {
23731    pub new_text: String,
23732    pub line_count_before: usize,
23733    pub line_count_after: usize,
23734}
23735
23736fn render_diff_hunk_controls(
23737    row: u32,
23738    status: &DiffHunkStatus,
23739    hunk_range: Range<Anchor>,
23740    is_created_file: bool,
23741    line_height: Pixels,
23742    editor: &Entity<Editor>,
23743    _window: &mut Window,
23744    cx: &mut App,
23745) -> AnyElement {
23746    h_flex()
23747        .h(line_height)
23748        .mr_1()
23749        .gap_1()
23750        .px_0p5()
23751        .pb_1()
23752        .border_x_1()
23753        .border_b_1()
23754        .border_color(cx.theme().colors().border_variant)
23755        .rounded_b_lg()
23756        .bg(cx.theme().colors().editor_background)
23757        .gap_1()
23758        .block_mouse_except_scroll()
23759        .shadow_md()
23760        .child(if status.has_secondary_hunk() {
23761            Button::new(("stage", row as u64), "Stage")
23762                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23763                .tooltip({
23764                    let focus_handle = editor.focus_handle(cx);
23765                    move |window, cx| {
23766                        Tooltip::for_action_in(
23767                            "Stage Hunk",
23768                            &::git::ToggleStaged,
23769                            &focus_handle,
23770                            window,
23771                            cx,
23772                        )
23773                    }
23774                })
23775                .on_click({
23776                    let editor = editor.clone();
23777                    move |_event, _window, cx| {
23778                        editor.update(cx, |editor, cx| {
23779                            editor.stage_or_unstage_diff_hunks(
23780                                true,
23781                                vec![hunk_range.start..hunk_range.start],
23782                                cx,
23783                            );
23784                        });
23785                    }
23786                })
23787        } else {
23788            Button::new(("unstage", row as u64), "Unstage")
23789                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23790                .tooltip({
23791                    let focus_handle = editor.focus_handle(cx);
23792                    move |window, cx| {
23793                        Tooltip::for_action_in(
23794                            "Unstage Hunk",
23795                            &::git::ToggleStaged,
23796                            &focus_handle,
23797                            window,
23798                            cx,
23799                        )
23800                    }
23801                })
23802                .on_click({
23803                    let editor = editor.clone();
23804                    move |_event, _window, cx| {
23805                        editor.update(cx, |editor, cx| {
23806                            editor.stage_or_unstage_diff_hunks(
23807                                false,
23808                                vec![hunk_range.start..hunk_range.start],
23809                                cx,
23810                            );
23811                        });
23812                    }
23813                })
23814        })
23815        .child(
23816            Button::new(("restore", row as u64), "Restore")
23817                .tooltip({
23818                    let focus_handle = editor.focus_handle(cx);
23819                    move |window, cx| {
23820                        Tooltip::for_action_in(
23821                            "Restore Hunk",
23822                            &::git::Restore,
23823                            &focus_handle,
23824                            window,
23825                            cx,
23826                        )
23827                    }
23828                })
23829                .on_click({
23830                    let editor = editor.clone();
23831                    move |_event, window, cx| {
23832                        editor.update(cx, |editor, cx| {
23833                            let snapshot = editor.snapshot(window, cx);
23834                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23835                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23836                        });
23837                    }
23838                })
23839                .disabled(is_created_file),
23840        )
23841        .when(
23842            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23843            |el| {
23844                el.child(
23845                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23846                        .shape(IconButtonShape::Square)
23847                        .icon_size(IconSize::Small)
23848                        // .disabled(!has_multiple_hunks)
23849                        .tooltip({
23850                            let focus_handle = editor.focus_handle(cx);
23851                            move |window, cx| {
23852                                Tooltip::for_action_in(
23853                                    "Next Hunk",
23854                                    &GoToHunk,
23855                                    &focus_handle,
23856                                    window,
23857                                    cx,
23858                                )
23859                            }
23860                        })
23861                        .on_click({
23862                            let editor = editor.clone();
23863                            move |_event, window, cx| {
23864                                editor.update(cx, |editor, cx| {
23865                                    let snapshot = editor.snapshot(window, cx);
23866                                    let position =
23867                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23868                                    editor.go_to_hunk_before_or_after_position(
23869                                        &snapshot,
23870                                        position,
23871                                        Direction::Next,
23872                                        window,
23873                                        cx,
23874                                    );
23875                                    editor.expand_selected_diff_hunks(cx);
23876                                });
23877                            }
23878                        }),
23879                )
23880                .child(
23881                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23882                        .shape(IconButtonShape::Square)
23883                        .icon_size(IconSize::Small)
23884                        // .disabled(!has_multiple_hunks)
23885                        .tooltip({
23886                            let focus_handle = editor.focus_handle(cx);
23887                            move |window, cx| {
23888                                Tooltip::for_action_in(
23889                                    "Previous Hunk",
23890                                    &GoToPreviousHunk,
23891                                    &focus_handle,
23892                                    window,
23893                                    cx,
23894                                )
23895                            }
23896                        })
23897                        .on_click({
23898                            let editor = editor.clone();
23899                            move |_event, window, cx| {
23900                                editor.update(cx, |editor, cx| {
23901                                    let snapshot = editor.snapshot(window, cx);
23902                                    let point =
23903                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23904                                    editor.go_to_hunk_before_or_after_position(
23905                                        &snapshot,
23906                                        point,
23907                                        Direction::Prev,
23908                                        window,
23909                                        cx,
23910                                    );
23911                                    editor.expand_selected_diff_hunks(cx);
23912                                });
23913                            }
23914                        }),
23915                )
23916            },
23917        )
23918        .into_any_element()
23919}